##// END OF EJS Templates
Reorganize models, smaller docker, others
jespinoza -
r2:ccdf3a6b9025
parent child
Show More
@@ -0,0 +1,110
1 [
2 {
3 "code" : 100,
4 "name" : "HF JRO"
5 },
6 {
7 "code" : 101,
8 "name" : "HF Huancayo"
9 },
10 {
11 "code" : 102,
12 "name" : "HF Ica"
13 },
14 {
15 "code" : 110,
16 "name" : "ISR EW Drifts"
17 },
18 {
19 "code" : 111,
20 "name" : "ISR Faraday"
21 },
22 {
23 "code" : 112,
24 "name" : "ISR Imaging"
25 },
26 {
27 "code" : 120,
28 "name" : "Faraday"
29 },
30 {
31 "code" : 121,
32 "name" : "Faraday Long Pulse"
33 },
34 {
35 "code" : 122,
36 "name" : "Faraday Codded LP"
37 },
38 {
39 "code" : 123,
40 "name" : "Faraday Double Pulse"
41 },
42 {
43 "code" : 124,
44 "name" : "Faraday AC"
45 },
46 {
47 "code" : 125,
48 "name" : "Faraday Differential Phase"
49 },
50 {
51 "code" : 150,
52 "name" : "JASMET 50"
53 },
54 {
55 "code" : 151,
56 "name" : "JASMET 30"
57 },
58 {
59 "code" : 170,
60 "name" : "BLTR Huancayo"
61 },
62 {
63 "code" : 171,
64 "name" : "CIRI Huancayo"
65 },
66 {
67 "code" : 172,
68 "name" : "CLAIRE Huancayo"
69 },
70 {
71 "code" : 180,
72 "name" : "MST"
73 },
74 {
75 "code" : 181,
76 "name" : "ISR"
77 },
78 {
79 "code" : 182,
80 "name" : "EEJ"
81 },
82 {
83 "code" : 190,
84 "name" : "JULIA 150km (Natalia)"
85 },
86 {
87 "code" : 191,
88 "name" : "JULIA SpreadF (Natalia)"
89 },
90 {
91 "code" : 200,
92 "name" : "JULIA 150km"
93 },
94 {
95 "code" : 201,
96 "name" : "JULIA EEJ"
97 },
98 {
99 "code" : 202,
100 "name" : "JULIA SpreadF"
101 },
102 {
103 "code" : 203,
104 "name" : "JULIA Imaging"
105 },
106 {
107 "code" : 203,
108 "name" : "JULIA Bistatic"
109 }
110 ] No newline at end of file
@@ -1,12 +1,12
1 1 FROM python:2.7-slim
2 2 RUN mkdir /app
3 3 WORKDIR /app
4 4 ADD requirements.txt ./requirements.txt
5 5 RUN apt-get clean && apt-get update && apt-get install -y --no-install-recommends \
6 6 g++ \
7 7 gcc \
8 8 && pip install -r requirements.txt \
9 && apt-get purge -y --auto-remove gcc g++\
9 && apt-get purge -y --auto-remove gcc g++ \
10 10 && rm -rf /var/lib/apt/lists/*
11 11 COPY . /app/
12 12 No newline at end of file
@@ -1,55 +1,55
1 1 version: '2'
2 2
3 3 services:
4 4 web:
5 5 container_name: 'realtime_web'
6 6 build: .
7 7 image: realtime
8 8 command: python manage.py runserver 0.0.0.0:8000
9 9 env_file: .env
10 10 ports:
11 11 - "8000:8000"
12 12 links:
13 13 - redis
14 14 - mongo
15 15 volumes:
16 16 - './:/app'
17 17 depends_on:
18 18 - redis
19 19 - mongo
20 20
21 21 zmq_server:
22 22 container_name: 'zmq_server'
23 23 image: 'realtime'
24 24 ports:
25 - '127.0.0.1:4444:4444'
25 - '4444:4444'
26 26 command: 'python -u scripts/server.py'
27 27 env_file: .env
28 28 links:
29 29 - redis
30 30 - mongo
31 31 volumes:
32 32 - './:/app'
33 33 depends_on:
34 34 - web
35 35
36 36 redis:
37 37 container_name: 'redis'
38 38 image: 'redis:3.2-alpine'
39 39 ports:
40 40 - '127.0.0.1:6379:6379'
41 41 volumes:
42 42 - 'redisdata:/data'
43 43
44 44 mongo:
45 45 container_name: 'mongo'
46 46 image: 'mongo:3.3'
47 47 command: '--storageEngine wiredTiger'
48 48 ports:
49 49 - '127.0.0.1:27017:27017'
50 50 volumes:
51 51 - 'mongodata:/data/db'
52 52
53 53 volumes:
54 54 redisdata:
55 55 mongodata: No newline at end of file
@@ -1,51 +1,52
1 1 import os
2 2 import json
3 import numpy as np
3
4 4 from datetime import datetime
5 5
6 6 from pymongo import MongoClient
7 7
8 from models import Experiment, Data
9
10 8 from channels.handler import AsgiHandler
11 9 from channels.auth import channel_session_user
12 10 from channels import Group
13 11
14 12 host = os.environ.get('HOST_MONGO', 'localhost')
15 13 CLIENT = MongoClient('{}:27017'.format(host))
16 14 DB = CLIENT['dbplots']
17 15
18 16 # Connected to websocket.connect
19 17 def ws_connect(message, code, plot):
20 # Accept the incoming connection
21 18 message.reply_channel.send({'accept': True})
22 # Add them to the chat group
23 Group('{}_{}'.format(code, plot)).add(message.reply_channel)
19 pk = message.content['query_string'].split('=')[1]
20 Group('{}_{}'.format(pk, plot)).add(message.reply_channel)
21 print('New connection from: {}, creating Group: {}_{}'.format(message.content['client'][0], pk, plot))
24 22
25 23 def ws_message(message, code, plot):
26 24 # Accept the incoming connection
27
25 print 'incoming message'
28 26 dt = datetime.strptime(str(json.loads(message.content['text'])['date']), '%d/%m/%Y')
29 e = DB.experiment.find_one({'date': dt})
30 if e:
27 exp = DB.exp_meta.find_one({'code': int(code), 'date': dt})
28 print exp
29 if exp:
31 30 if plot == 'spc':
32 datas = DB.data.find({'experiment': e['_id']}, ['time', 'data']).sort('time', -1).limit(1)[0]
33 e['time'] = [datas['time']]
34 e['spc'] = datas['data']['spc']
35 e['rti'] = datas['data']['rti']
36 e['noise'] = datas['data']['noise']
31 datas = DB.exp_data.find({'expmeta': exp['_id']}, ['time', 'data']).sort('time', -1).limit(1)[0]
32 exp['time'] = [datas['time']]
33 exp['spc'] = datas['data']['spc']
34 exp['rti'] = datas['data']['rti']
35 exp['noise'] = datas['data']['noise']
37 36 else:
38 datas = DB.data.find({'experiment': e['_id']}, ['time', 'data']).sort('time', 1)
37 datas = DB.exp_data.find({'expmeta': exp['_id']}, ['time', 'data']).sort('time', 1)
38 print 'Counting...'
39 print datas.count()
39 40 dum = [(d['time'], d['data'][plot]) for d in datas]
40 e['time'] = [d[0] for d in dum]
41 exp['time'] = [d[0] for d in dum]
41 42 dum = [d[1] for d in dum]
42 e[plot] = map(list, zip(*dum))
43 e.pop('date', None)
44 e.pop('_id', None)
45 message.reply_channel.send({'text': json.dumps(e)})
43 exp[plot] = map(list, zip(*dum))
44 exp.pop('date', None)
45 exp.pop('_id', None)
46 message.reply_channel.send({'text': json.dumps(exp)})
46 47 else:
47 48 message.reply_channel.send({'text': json.dumps({'interval': 0})})
48 49
49 50 # Connected to websocket.disconnect
50 51 def ws_disconnect(message, code, plot):
51 52 Group('{}_{}'.format(code, plot)).discard(message.reply_channel)
@@ -1,31 +1,33
1 1 # -*- coding: utf-8 -*-
2 2 from __future__ import unicode_literals
3 3
4 4 from django.db import models
5 5 from mongoengine import *
6 6
7 7 class Experiment(Document):
8 code = IntField(unique=True)
9 name = StringField(max_length=40)
10
11 class ExpMeta(Document):
8 12 code = IntField()
9 name = StringField(max_length=40, default='Experiment')
10 13 date = DateTimeField()
11 14 pairs = ListField(default=list)
12 15 yrange = ListField(FloatField())
13 16 xrange = ListField(FloatField())
14 17 interval = FloatField()
18 plots = ListField(StringField())
15 19 localtime = BooleanField()
16 20
17 21 meta = {
18 22 'indexes': [[("code", 1), ("date", 1)]]
19 23 }
20 24
21 class Data(Document):
22 experiment = LazyReferenceField(Experiment)
25 class ExpData(Document):
26 expmeta = LazyReferenceField(ExpMeta)
23 27 time = FloatField()
24 28 data = DictField()
25 29
26 30 meta = {
27 'indexes': ["experiment", "+time"]
31 'indexes': ["expmeta", "+time"]
28 32 }
29 33
30 # connect('dbplots')
31 # Experiment.drop_collection()
@@ -1,454 +1,454
1 1
2 2
3 3 class PcolorBuffer{
4 4 constructor({div, data, key, props}){
5 5 this.div = document.getElementById(div);
6 6 this.n = 0
7 7 this.divs = [];
8 8 this.wait = false;
9 9 this.key = key;
10 10 this.timer = (props.throttle || 30)*1000;
11 11 this.lastRan = Date.now();
12 12 this.lastFunc = null;
13 13 this.zbuffer = [];
14 14 this.xbuffer = [];
15 15 this.empty = Array(data.yrange.length).fill(null);
16 16 this.props = props;
17 17 this.setup(data);
18 18 }
19 19
20 20 setup(data){
21 21 this.last = data.time.slice(-1);
22 22 if (data.time.length == 1){
23 23 var values = { 'time': data.time, 'data': data[this.key].map(function(x) {return [x]})};
24 24 }else{
25 25 var values = this.fill_gaps(data.time, data[this.key], data.interval, data[this.key].length);
26 26 }
27 27
28 28 var t = values.time.map(function(x) { return new Date(x*1000); });
29 29
30 30 for (var i = 0; i < data[this.key].length; i++){
31 31 var layout = {
32 32 xaxis: {
33 33 title: 'Time',
34 34 showgrid: false,
35 35 },
36 36 yaxis: {
37 37 title: 'km',
38 38 showgrid: false,
39 39 },
40 40 titlefont: {
41 41 size: 14,
42 42 }
43 43 };
44 44 var iDiv = document.createElement('div');
45 45 iDiv.id = 'plot-' + i;
46 46 this.zbuffer.push([]);
47 47 this.n = this.n + 1;
48 48 this.div.appendChild(iDiv);
49 49 this.divs.push(iDiv.id);
50 50 var trace = {
51 51 z: values.data[i],
52 52 x: t,
53 53 y: data.yrange,
54 54 colorscale: this.props.colormap || 'Viridis',
55 55 transpose: true,
56 56 type: 'heatmap'
57 57 };
58 58
59 59 if (this.props.zmin) {trace.zmin = this.props.zmin}
60 60 if (this.props.zmax) {trace.zmax = this.props.zmax}
61 61
62 62 layout.title = 'Channel ' + i + ' - ' + t.slice(-1).toLocaleString();
63 63 var conf = {
64 64 modeBarButtonsToRemove: ['sendDataToCloud', 'autoScale2d', 'hoverClosestCartesian', 'hoverCompareCartesian', 'lasso2d', 'select2d', 'zoomIn2d', 'zoomOut2d', 'toggleSpikelines'],
65 65 displaylogo: false,
66 66 showTips: true
67 67 };
68 68 Plotly.newPlot('plot-'+i, [trace], layout, conf);
69 69 }
70 70 }
71 71
72 72 getSize(){
73 73 var div = document.getElementById(this.divs[0]);
74 74 var t = this.xbuffer.slice(-1)[0];
75 75 var n = 0;
76 76 var timespan = (this.props.timespan || 8)*1000*60*60;
77 77
78 78 while ((t-div.data[0].x[n]) > timespan){
79 79 n += 1;
80 80 }
81 81 return n;
82 82 }
83 83
84 84 fill_gaps(xBuffer, zBuffer, interval, N){
85 85
86 86 var x = [xBuffer[0]];
87 87 var z = [];
88 88 var last;
89 89
90 90 for (var j = 0; j < N; j++){
91 91 z.push([zBuffer[j][0]]);
92 92 }
93 93
94 94 for (var i = 1; i < xBuffer.length; i++){
95 95 var cnt = 0;
96 96 last = x.slice(-1)[0];
97 97 while (Math.abs(parseFloat(xBuffer[i])-last-parseFloat(interval))>0.5){
98 98 cnt += 1;
99 99 last = last+interval;
100 100 x.push(last);
101 101 for (var j = 0; j < N; j++){
102 102 z[j].push(this.empty);
103 103 }
104 104 // Avoid infinite loop
105 105 if (cnt==100){break;}
106 106 }
107 107 x.push(xBuffer[i]);
108 108 for (var j = 0; j < N; j++){
109 109 z[j].push(zBuffer[j][i]);
110 110 }
111 111 }
112 112
113 113 return {'time':x, 'data':z};
114 114 }
115 115
116 116 plot(){
117 117 // add new data to plots and empty buffers
118 118 var N = this.getSize();
119 119 console.log('Plotting...');
120 120 for (var i = 0; i < this.n; i++){
121 121 var div = document.getElementById(this.divs[i]);
122 122 if (N > 0){
123 123 div.data[0].z = div.data[0].z.slice(N,)
124 124 div.data[0].x = div.data[0].x.slice(N,)
125 125 }
126 126 Plotly.extendTraces(div, {
127 127 z: [this.zbuffer[i]],
128 128 x: [this.xbuffer]
129 129 }, [0]);
130 130 this.zbuffer[i] = [];
131 131 }
132 132 this.xbuffer = [];
133 133 }
134 134
135 135 update(obj){
136 136
137 137 // fill data gaps
138 138 var cnt = 0;
139 139 while (Math.abs(parseFloat(obj.time[0])-this.last-parseFloat(obj.interval))>0.5){
140 140 cnt += 1;
141 141 this.last += obj.interval;
142 142 var newt = new Date((this.last)*1000);
143 143 this.xbuffer.push(newt);
144 144 for (var i = 0; i < obj[this.key].length; i++){
145 145 this.zbuffer[i].push(this.empty);
146 146 }
147 147 // Avoid infinite loop
148 148 if (cnt==100){break;}
149 149 }
150 150
151 151 // update buffers
152 152 this.last = parseFloat(obj.time[0]);
153 153 var t = new Date(obj.time[0]*1000);
154 154 this.xbuffer.push(t);
155 155 for (var i = 0; i < obj[this.key].length; i++){
156 156 this.zbuffer[i].push(obj[this.key][i]);
157 157 // update title
158 158 var div = document.getElementById(this.divs[i]);
159 159 Plotly.relayout(div, {
160 160 title: 'Channel ' + i + ' - ' + t.toLocaleString(),
161 161 });
162 162 }
163 163
164 164 // plot when ready (every 10 secs)
165 165 if (!this.wait){
166 166 this.plot();
167 167 this.wait = true;
168 168 } else {
169 169 clearTimeout(this.lastFunc)
170 170 this.lastFunc = setTimeout(function(scope) {
171 171 if ((Date.now() - scope.lastRan) >= scope.timer) {
172 172 scope.plot()
173 173 scope.lastRan = Date.now()
174 174 }
175 175 }, this.timer - (Date.now() - this.lastRan), this)
176 176 }
177 177 }
178 178 }
179 179
180 180 class Pcolor{
181 181 constructor({div, data, props}){
182 182 this.div = document.getElementById(div);
183 183 this.n = 0
184 184 this.divs = [];
185 185 this.props = props;
186 186 this.setup(data);
187 187 }
188 188
189 189 setup(data){
190 190 console.log(data);
191 191 for (var i = 0; i < data.spc.length; i++){
192 192 var layout = {
193 193 height: 400,
194 194 xaxis: {
195 195 title: 'Velocity',
196 196 showgrid: false,
197 197 zeroline: false,
198 198 domain: [0, 0.7],
199 199 },
200 200 yaxis: {
201 201 title: 'km',
202 202 showgrid: false,
203 203 },
204 204 xaxis2: {
205 205 title: 'dB',
206 206 domain: [0.75, 1],
207 207 ticks: 'outside',
208 208 },
209 209 titlefont: {
210 210 size: 14,
211 211 }
212 212 };
213 213 var iDiv = document.createElement('div');
214 214 iDiv.id = 'plot-' + i;
215 215 iDiv.className += iDiv.className ? ' col-md-6' : 'col-md-6';
216 216 this.n = this.n + 1;
217 217 this.div.appendChild(iDiv);
218 218 this.divs.push(iDiv.id);
219 219
220 220 var trace1 = {
221 221 z: data.spc[i],
222 222 x: data.xrange,
223 223 y: data.yrange,
224 224 colorscale: this.props.colormap || 'Viridis',
225 225 transpose: true,
226 226 type: 'heatmap'
227 227 };
228 228
229 229 var trace2 = {
230 230 x: data.rti[i],
231 231 y: data.yrange,
232 232 xaxis: 'x2',
233 233 yaxis: 'y',
234 234 type: 'scatter',
235 235 };
236 236
237 237 if (this.props.zmin) {
238 238 trace1.zmin = this.props.zmin
239 239 }
240 240 if (this.props.zmax) {
241 241 trace1.zmax = this.props.zmax;
242 242 layout.xaxis2.range = [this.props.zmin, this.props.zmax]
243 243 }
244 244
245 245 var t = new Date(data.time*1000);
246 246 layout.title = 'Channel ' + i + ': ' + data.noise[i]+'dB - ' + t.toLocaleString();
247 247 var conf = {
248 248 modeBarButtonsToRemove: ['sendDataToCloud', 'autoScale2d', 'hoverClosestCartesian', 'hoverCompareCartesian', 'lasso2d', 'select2d', 'zoomIn2d', 'zoomOut2d', 'toggleSpikelines'],
249 249 displaylogo: false,
250 250 showTips: true
251 251 };
252 252 Plotly.newPlot('plot-'+i, [trace1, trace2], layout, conf);
253 253 }
254 254 }
255 255
256 256 plot(obj){
257 257
258 258 // add new data to plots and empty buffers
259 259 console.log('Plotting...');
260 260 var t = new Date(obj.time[0]*1000);
261 261 for (var i = 0; i < this.n; i++){
262 262 var div = document.getElementById(this.divs[i]);
263 263 Plotly.relayout(div, {
264 264 title: 'Channel ' + i + ': ' + obj.noise[i]+'dB - ' + t.toLocaleString(),
265 265 });
266 266 Plotly.restyle(div, {
267 267 z: [obj.spc[i], null],
268 268 x: [obj.xrange, obj.rti[i]]
269 269 }, [0, 1]);
270 270 }
271 271 }
272 272 }
273 273
274 274 class Scatter{
275 275 constructor({div, data, key, props}){
276 276 this.div = document.getElementById(div);
277 277 this.n = 0
278 278 this.key = key;
279 279 this.wait = false;
280 280 this.timer = (props.throttle || 30)*1000;
281 281 this.lastRan = Date.now();
282 282 this.lastFunc = null;
283 283 this.ybuffer = [];
284 284 this.xbuffer = [];
285 285 this.props = props;
286 286 this.setup(data);
287 287 }
288 288
289 289 setup(data){
290 290
291 291 var traces = [];
292 292 this.last = data.time.slice(-1);
293 293 if (data.time.length == 1){
294 294 var values = { 'time': data.time, 'data': data[this.key] };
295 295 }else{
296 296 var values = this.fill_gaps(data.time, data[this.key], data.interval, data[this.key].length);
297 297 }
298 298
299 299 var t = values.time.map(function(x) { return new Date(x*1000); });
300 300
301 301 for (var i = 0; i < data[this.key].length; i++){
302 302
303 303 this.n = this.n + 1;
304 304 this.ybuffer.push([]);
305 305 var trace = {
306 306 x: t,
307 307 y: data[this.key][i],
308 308 mode: 'lines',
309 309 type: 'scatter',
310 310 name: 'Channel ' + i
311 311 };
312 312
313 313 traces.push(trace);
314 314 }
315 315 var title = this.props.title || ''
316 316 var layout = {
317 317 // autosize: false,
318 318 // width: 800,
319 319 // height: 400,
320 320 title: title + ' - ' + t.slice(-1).toLocaleString(),
321 321 xaxis: {
322 322 title: 'Time',
323 323 linecolor: 'black',
324 324 },
325 325 yaxis: {
326 326 title: this.props.ylabel || 'dB',
327 327 linecolor: 'black',
328 328 },
329 329 titlefont: {
330 330 size: 14,
331 331 }
332 332 };
333 333
334 334 if (this.props.ymin) {layout.yaxis.range = [this.props.ymin, this.props.ymax] }
335 335
336 336 var conf = {
337 337 modeBarButtonsToRemove: ['sendDataToCloud', 'autoScale2d', 'hoverClosestCartesian', 'hoverCompareCartesian', 'lasso2d', 'select2d', 'zoomIn2d', 'zoomOut2d', 'toggleSpikelines'],
338 338 displaylogo: false,
339 339 showTips: true
340 340 };
341 341 Plotly.newPlot('plot', traces, layout, conf);
342 342 }
343 343
344 344 getSize(){
345 345 var t = this.xbuffer.slice(-1)[0];
346 346 var n = 0;
347 347 var timespan = (this.props.timespan || 12)*1000*60*60;
348 348
349 349 while ((t-this.div.data[0].x[n]) > timespan){
350 350 n += 1;
351 351 }
352 352 return n;
353 353 }
354 354
355 355 fill_gaps(xBuffer, yBuffer, interval, N){
356 356
357 357 var x = [xBuffer[0]];
358 358 var y = [];
359 359
360 360 for (var j = 0; j < N; j++){
361 361 y.push([yBuffer[j][0]]);
362 362 }
363 363
364 364 var last;
365 365
366 366 for (var i = 1; i < xBuffer.length; i++){
367 367 var cnt = 0;
368 368 last = x.slice(-1)[0];
369 369 while (Math.abs(parseFloat(xBuffer[i])-last-parseFloat(interval))>0.5){
370 370 cnt += 1;
371 371 last = last+interval;
372 372 x.push(last);
373 373 for (var j = 0; j < N; j++){
374 z[j].push(null);
374 y[j].push(null);
375 375 }
376 376 // Avoid infinite loop
377 377 if (cnt==100){break;}
378 378 }
379 379 x.push(xBuffer[i]);
380 380
381 381 for (var j = 0; j < N; j++){
382 382 y[j].push(yBuffer[j][i]);
383 383 }
384 384 }
385 385 return {'time':x, 'data':y};
386 386 }
387 387
388 388 plot(){
389 389 // add new data to plots and empty buffers
390 390 var xvalues = [];
391 391 var yvalues = [];
392 392 var traces = [];
393 393 var N = this.getSize();
394 394 console.log('Plotting...');
395 395 for (var i = 0; i < this.n; i++){
396 396 if (N > 0){
397 397 this.div.data[i].y = this.div.data[i].y.slice(N,)
398 398 this.div.data[i].x = this.div.data[i].x.slice(N,)
399 399 }
400 400 yvalues.push(this.ybuffer[i]);
401 401 xvalues.push(this.xbuffer);
402 402 traces.push(i);
403 403 this.ybuffer[i] = [];
404 404 }
405 405 Plotly.extendTraces(this.div, {
406 406 y: yvalues,
407 407 x: xvalues
408 408 }, traces);
409 409 this.xbuffer = [];
410 410 }
411 411
412 412 update(obj){
413 413
414 414 // fill data gaps
415 415 var cnt = 0;
416 416 while (Math.abs(parseFloat(obj.time[0])-this.last-parseFloat(obj.interval))>0.5){
417 417 cnt += 1;
418 418 this.last += obj.interval;
419 419 var newt = new Date((this.last)*1000);
420 420 this.xbuffer.push(newt);
421 421 for (var i = 0; i < this.n; i++){
422 422 this.ybuffer[i].push(null);
423 423 }
424 424 // Avoid infinite loop
425 425 if (cnt==100){break;}
426 426 }
427 427
428 428 // update buffers
429 429 this.last = parseFloat(obj.time[0]);
430 430 var t = new Date(obj.time[0]*1000);
431 431 this.xbuffer.push(t);
432 432 for (var i = 0; i < this.n; i++){
433 433 this.ybuffer[i].push(obj[this.key][i][0]);
434 434 }
435 435 var title = this.props.title || ''
436 436 Plotly.relayout(this.div, {
437 437 title: title + ' - ' + t.toLocaleString(),
438 438 });
439 439
440 440 // plot when ready (every 10 secs)
441 441 if (!this.wait){
442 442 this.plot();
443 443 this.wait = true;
444 444 } else {
445 445 clearTimeout(this.lastFunc)
446 446 this.lastFunc = setTimeout(function(scope) {
447 447 if ((Date.now() - scope.lastRan) >= scope.timer) {
448 448 scope.plot()
449 449 scope.lastRan = Date.now()
450 450 }
451 451 }, this.timer - (Date.now() - this.lastRan), this)
452 452 }
453 453 }
454 454 }
@@ -1,112 +1,118
1 1 {% load static %} {% load bootstrap3 %}
2 2 <!doctype html>
3 3 <html lang="en">
4 4
5 5 <head>
6 6 <meta charset="utf-8">
7 7 <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
8 8 <meta http-equiv="X-UA-Compatible" content="ie=edge">
9 9 <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
10 10 <link href="{% static 'css/bootstrap-datetimepicker.min.css' %}" media="screen" rel="stylesheet">
11 11 <script src="{% static 'js/jquery.min.js' %}"></script>
12 12 <style>
13 13 /* Paste this css to your style sheet file or under head tag */
14 14
15 15 /* This only works with JavaScript,
16 16 if it's not present, don't show loader */
17 17
18 18 .loader {
19 19 width: 100%;
20 20 height: 10px;
21 21 position: relative;
22 22 z-index: 9999;
23 23 background: url("{% static 'images/loader.gif' %}") center no-repeat #fff;
24 24 }
25 25
26 26 .no-data {
27 27 text-align: center;
28 28 background-color: #d58512;
29 29 padding: 8px 16px;
30 30 border-radius: 5px;
31 31 color: #FEFEFE;
32 32 font: 20px 'Helvetica';
33 33 text-transform: uppercase;
34 34 }
35 35 </style>
36 36 <title>Realtime plots at JRO</title>
37 37 </head>
38 38
39 39 <body>
40 40 <div class="container">
41 41 <div id="page" class="row" style="min-height:600px">
42 42 {% bootstrap_messages %}
43 43 <div class="page-header">
44 44 <h1>{% block content-title %}Realtime{% endblock %}
45 45 <small>{% block content-suptitle %}Plots{% endblock %}</small>
46 46 </h1>
47 47 </div>
48 48 <div class="col-md-3 hidden-xs hidden-sm" role="complementary">
49 49 <div id="sidebar">
50 50 {% if form.is_multipart %}
51 51 <form class="form" enctype="multipart/form-data" method="post" action="{{action}}">
52 52 {% else %}
53 53 <form class="form" method="post" action="{{action}}">
54 54 {% endif %} {% csrf_token %} {% bootstrap_form form layout='inline' size='medium' %}
55 55 <div style="clear: both;"></div>
56 56 <br>
57 57 <div class="pull-left">
58 58 <button type="button" id="bt_show" class="btn btn-primary">Show</button>
59 59 </div>
60 60 </form>
61 61 </div>
62 62 </div>
63 63 <div class="col-md-9 col-xs-12" role="main">
64 64 <div id="loader" class="loader"></div>
65 65 {% block content %} {% endblock %}
66 66 </div>
67 67 </div>
68 68 <!--/row-->
69 69 </div>
70 70 <script src="{% static 'js/plotly-latest.min.js' %}"></script>
71 71 <script src="{% static 'js/moment.min.js' %}"></script>
72 72 <script src="{% static 'js/bootstrap-datetimepicker.min.js' %}"></script>
73 73 <script src="{% static 'js/jroplots.js' %}"></script>
74 74 <script type="text/javascript">
75 75 $('#id_date').datetimepicker({
76 76 pickTime: false,
77 77 format: 'DD/MM/YYYY',
78 78 });
79 79 $("#bt_show").click(function () {
80 80 document.location = '/' + $("#id_experiment").val() + '/' + $("#id_plot").val() + '/?date=' + $("#id_date").val();
81 81 });
82 82
83 var socket = new WebSocket('ws://' + window.location.host + '/{{code}}/{{plot}}/');
83 {% if date %}
84 $("#loader").css("display", "block");
85 var socket = new WebSocket('ws://' + window.location.host + '/{{code}}/{{plot}}/?' + 'pk={{id}}');
84 86 socket.onopen = function open() {
85 87 console.log('WebSockets connection created.');
86 88 {% if date %}
87 89 socket.send('{"date": "{{date}}" }');
88 90 {% else %}
89 91 socket.send('{"date": "{% now "d/m/Y" %}" }');
90 92 {% endif %}
91 93 };
92 94
93 95 socket.onmessage = function message(event) {
94 96 var data = JSON.parse(event.data);
97 console.log(data);
95 98 if (data.interval == 0) {
96 99 $("#loader").removeClass("loader").addClass("no-data");
97 100 $("#loader").html("No data found");
98 101 } else {
99 102 var first = plot(data);
100 if (first == true) {
101 $("#loader").css("display", "none");
103 if (first == true) {
104 $("#loader").css("display", "none");
102 105 }
103 106 }
104 107 }
105 108
106 109 if (socket.readyState == WebSocket.OPEN) {
107 110 socket.onopen();
108 111 }
112 {% else %}
113 $("#loader").css("display", "none");
114 {% endif %}
109 115 </script> {% block script %}{% endblock script %}
110 116 </body>
111 117
112 118 </html> No newline at end of file
@@ -1,81 +1,84
1 1 # -*- coding: utf-8 -*-
2 2 from __future__ import unicode_literals
3 3
4 4 import os
5 5 from datetime import datetime
6 6
7 7 from django import forms
8 8 from django.contrib import messages
9 9 from django.utils.safestring import mark_safe
10 10 from django.shortcuts import render
11 11
12 12 from bootstrap3_datetime.widgets import DateTimePicker
13 13
14 from pymongo import MongoClient
14 import mongoengine
15 15
16 host = os.environ.get('HOST_MONGO', 'localhost')
16 from plotter.models import Experiment, ExpMeta
17 17
18 CLIENT = MongoClient('{}:27017'.format(host))
19 DB = CLIENT['dbplots']
18 host = os.environ.get('HOST_MONGO', 'localhost')
19 mongoengine.connect('dbplots', host=host, port=27017)
20 20
21 21 # Forms
22 22 class SearchForm(forms.Form):
23 23
24 24 experiment = forms.ChoiceField()
25 25 plot = forms.ChoiceField(
26 26 choices = [(0, 'Select Plot'), ('rti', 'RTI'),('spc', 'Spectra'),('noise', 'Noise')]
27 27 )
28 28 date = forms.DateField(
29 29 widget=DateTimePicker(options={"format": "DD/MM/YYYY"})
30 30 )
31 31
32 32 def __init__(self, *args, **kwargs):
33 33
34 34 exp_choices = kwargs.pop('exp_choices', [])
35 35 super(SearchForm, self).__init__(*args, **kwargs)
36 36 self.fields['experiment'].choices = [(0, 'Select Experiment')] + exp_choices
37 37
38 38 # Create your views here.
39 39 def main(request, code=None, plot=None):
40 40
41 41 initial = {}
42 42 date = request.GET.get('date', datetime.now().strftime('%d/%m/%Y'))
43 43 initial['date'] = date
44 44
45 45 if code is not None:
46 46 initial['experiment'] = code
47 47 if plot is not None:
48 48 initial['plot'] = plot
49 49
50 print 'hola'
51 codes = DB.experiment.find().distinct('code')
52 print codes
53 exps = [DB.experiment.find_one({'code': c}, ['name']) for c in codes]
54 print exps
55 names = [q['name'] for q in exps]
56 print names
50 exps = [(q['code'], q['name']) for q in Experiment.objects.all()]
51
57 52 form = SearchForm(
58 53 initial = initial,
59 exp_choices = [(e[0], e[1]) for e in zip(codes, names)]
54 exp_choices = [(e[0], e[1]) for e in exps]
60 55 )
61 56
57 try:
58 exp = ExpMeta.objects.get(code=int(code), date=datetime.strptime(date, '%d/%m/%Y'))
59 exp_id = exp.id
60 except:
61 exp_id = 0
62
63
62 64 kwargs = {
63 65 'code': code,
64 66 'plot': plot,
65 67 'date': date,
66 68 'form': form,
69 'id': exp_id
67 70 }
68 71
69 if code and codes:
70 kwargs['title'] = [t[1] for t in zip(codes, names) if t[0]==int(code)][0]
72 if code and exps:
73 kwargs['title'] = [t[1] for t in exps if t[0]==int(code)][0]
71 74 else:
72 75 kwargs['title'] = 'JRO'
73 76
74 77 if plot == 'rti':
75 78 return render(request, 'rti.html', kwargs)
76 79 elif plot == 'spc':
77 80 return render(request, 'spectra.html', kwargs)
78 81 elif plot == 'noise':
79 82 return render(request, 'scatter.html', kwargs)
80 83 else:
81 84 return render(request, 'base.html', kwargs) No newline at end of file
@@ -1,8 +1,8
1 1 from channels.routing import route
2 2 from plotter.consumers import ws_connect, ws_disconnect, ws_message
3 3
4 4 channel_routing = [
5 5 route("websocket.connect", ws_connect, path=r'^/(?P<code>[0-9]+)/(?P<plot>[a-z]+)/$'),
6 6 route("websocket.receive", ws_message, path=r'^/(?P<code>[0-9]+)/(?P<plot>[a-z]+)/$'),
7 7 route("websocket.disconnect", ws_disconnect, path=r'^/(?P<code>[0-9]+)/(?P<plot>[a-z]+)/$'),
8 ] No newline at end of file
8 ]
@@ -1,135 +1,135
1 1 """
2 2 Django settings for realtime project.
3 3
4 4 Generated by 'django-admin startproject' using Django 1.11.7.
5 5
6 6 For more information on this file, see
7 7 https://docs.djangoproject.com/en/1.11/topics/settings/
8 8
9 9 For the full list of settings and their values, see
10 10 https://docs.djangoproject.com/en/1.11/ref/settings/
11 11 """
12 12
13 13 import os
14 14
15 15 # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
16 16 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17 17
18 18
19 19 # Quick-start development settings - unsuitable for production
20 20 # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
21 21
22 22 # SECURITY WARNING: keep the secret key used in production secret!
23 23 SECRET_KEY = '(htjox+v27sda)$61vjhuveeh_q$gw5+z^cn71!h2m-!!s!7ra'
24 24
25 25 # SECURITY WARNING: don't run with debug turned on in production!
26 26 DEBUG = True
27 27
28 28 ALLOWED_HOSTS = ['*']
29 29
30 30
31 31 # Application definition
32 32
33 33 INSTALLED_APPS = [
34 34 'django.contrib.admin',
35 35 'django.contrib.auth',
36 36 'django.contrib.contenttypes',
37 37 'django.contrib.sessions',
38 38 'django.contrib.messages',
39 39 'django.contrib.staticfiles',
40 40 'bootstrap3',
41 41 'channels',
42 42 'plotter',
43 43 ]
44 44
45 45 MIDDLEWARE = [
46 46 'django.middleware.security.SecurityMiddleware',
47 47 'django.contrib.sessions.middleware.SessionMiddleware',
48 48 'django.middleware.common.CommonMiddleware',
49 49 'django.middleware.csrf.CsrfViewMiddleware',
50 50 'django.contrib.auth.middleware.AuthenticationMiddleware',
51 51 'django.contrib.messages.middleware.MessageMiddleware',
52 52 'django.middleware.clickjacking.XFrameOptionsMiddleware',
53 53 ]
54 54
55 55 ROOT_URLCONF = 'realtime.urls'
56 56
57 57 TEMPLATES = [
58 58 {
59 59 'BACKEND': 'django.template.backends.django.DjangoTemplates',
60 60 'DIRS': [],
61 61 'APP_DIRS': True,
62 62 'OPTIONS': {
63 63 'context_processors': [
64 64 'django.template.context_processors.debug',
65 65 'django.template.context_processors.request',
66 66 'django.contrib.auth.context_processors.auth',
67 67 'django.contrib.messages.context_processors.messages',
68 68 ],
69 69 },
70 70 },
71 71 ]
72 72
73 73 WSGI_APPLICATION = 'realtime.wsgi.application'
74 74
75 75
76 76 # Database
77 77 # https://docs.djangoproject.com/en/1.11/ref/settings/#databases
78 78
79 79 DATABASES = {
80 80 'default': {
81 81 'ENGINE': 'django.db.backends.sqlite3',
82 82 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
83 83 }
84 84 }
85 85
86 86
87 87 # Password validation
88 88 # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
89 89
90 90 AUTH_PASSWORD_VALIDATORS = [
91 91 {
92 92 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
93 93 },
94 94 {
95 95 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
96 96 },
97 97 {
98 98 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
99 99 },
100 100 {
101 101 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
102 102 },
103 103 ]
104 104
105 105
106 106 # Internationalization
107 107 # https://docs.djangoproject.com/en/1.11/topics/i18n/
108 108
109 109 LANGUAGE_CODE = 'en-us'
110 110
111 111 TIME_ZONE = 'UTC'
112 112
113 113 USE_I18N = True
114 114
115 115 USE_L10N = True
116 116
117 117 USE_TZ = True
118 118
119 119
120 120 # Static files (CSS, JavaScript, Images)
121 121 # https://docs.djangoproject.com/en/1.11/howto/static-files/
122 122
123 123 STATIC_URL = '/static/'
124 124
125 host = os.environ.get('HOST_REDIS', 'localhost')
125 host = os.environ.get('HOST_REDIS', '127.0.0.1')
126 126
127 127 CHANNEL_LAYERS = {
128 128 "default": {
129 129 "BACKEND": "asgi_redis.RedisChannelLayer",
130 130 "CONFIG": {
131 131 "hosts": [(host, 6379)],
132 132 },
133 133 "ROUTING": "realtime.routing.channel_routing",
134 134 },
135 135 } No newline at end of file
@@ -1,12 +1,11
1 1 asgi-redis==1.4.3
2 2 Django==1.11.7
3 3 django-bootstrap3==9.1.0
4 4 django-bootstrap3-datetimepicker-2==2.5.0
5 5 channels==1.1.8
6 6 mongoengine==0.15.0
7 numpy==1.13.3
8 7 pymongo==3.5.1
9 8 pyzmq==16.0.3
10 9 redis==2.10.6
11 10 requests==2.18.4
12 11 simplejson==3.12.0
@@ -1,94 +1,84
1 1 import os
2 2 import sys
3 import json
3 4 import simplejson
4 5 from datetime import datetime
5 6 import zmq
6 7 import redis
7 8 import asgi_redis
8 9 import mongoengine
9 10
10 11 sys.path.append('/app')
11 12 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "realtime.settings")
12 13
13 from plotter.models import Experiment, Data
14
14 from plotter.models import Experiment, ExpMeta, ExpData
15 15
16 16 host_mongo = os.environ.get('HOST_MONGO', 'localhost')
17 17 mongoengine.connect('dbplots', host=host_mongo, port=27017)
18 18
19 19
20 20 host_redis = os.environ.get('HOST_REDIS', 'localhost')
21 21 channel = asgi_redis.RedisChannelLayer(hosts=[(host_redis, 6379)])
22 22
23 23 context = zmq.Context()
24 24 receiver = context.socket(zmq.SUB)
25 25
26 26 receiver.bind("tcp://0.0.0.0:4444")
27 27 receiver.setsockopt(zmq.SUBSCRIBE, '')
28 28
29
30
31 def update_db(buffer):
32 dt = datetime.utcfromtimestamp(buffer['time'])
33 exp = Experiment.objects(code=buffer['exp_code'], date=dt.date()).first()
34 if exp is None:
35 exp = Experiment(
36 code=buffer['exp_code'],
37 date=dt.date(),
38 yrange = buffer['yrange'],
39 xrange = buffer['xrange'],
40 interval = buffer['interval'],
41 localtime = buffer['localtime'],
42 name = buffer['name'],
29 def loaddata():
30 print('Loading Experiments...')
31 for tup in json.load(open('scripts/experiments.json')):
32 print(tup['name'])
33 exp = Experiment.objects(code=tup['code']).modify(
34 upsert=True,
35 new=True,
36 set__code=tup['code'],
37 set__name=tup['name'],
43 38 )
44 39 exp.save()
40
41 def update(buffer):
42 dt = datetime.utcfromtimestamp(buffer['time'])
43 exp = ExpMeta.objects(code=buffer['exp_code'], date=dt.date()).modify(
44 upsert=True,
45 new=True,
46 set__code=buffer['exp_code'],
47 set__date=dt.date(),
48 set__yrange = buffer['yrange'],
49 set__xrange = buffer['xrange'],
50 set__interval = buffer['interval'],
51 set__localtime = buffer['localtime'],
52 set__plots = buffer['data'].keys()
53 )
54 exp.save()
45 55
46 data = Data.objects(experiment=exp, time=buffer['time']).first()
56 data = ExpData.objects(expmeta=exp, time=buffer['time']).modify(
57 upsert=True,
58 new=True,
59 set__expmeta = exp,
60 set__time = buffer['time'],
61 set__data = buffer['data']
62 )
47 63
48 if data is None:
49 data = Data(
50 experiment = exp,
51 time = buffer['time'],
52 data = buffer['data']
53 ).save()
54 new = True
55 else:
56 data.data = buffer['data']
57 data.save()
58 new = False
64 data.save()
59 65
60 return new
61 print 'Starting...'
62 while True:
63 buffer = receiver.recv_json()
64 if 'xrange' not in buffer:
65 buffer['xrange'] = []
66 if 'name' not in buffer:
67 buffer['name'] = 'Experiment'
68 if update_db(buffer):
69 dum = buffer.copy()
70 dum['time'] = [buffer['time']]
71 dum['rti'] = buffer['data']['rti']
72 # dum['noise'] = buffer['data']['noise']
73 dum.pop('data')
74 code = dum.pop('exp_code')
75 channel.send_group(u'{}_rti'.format(code), {'text': simplejson.dumps(dum, ignore_nan=True)})
76 print 'Sending...{} - {} bytes'.format('rti', len(str(dum)))
66 return exp.id
77 67
78 # dum = buffer.copy()
79 # dum['time'] = [buffer['time']]
80 # dum['rti'] = buffer['data']['rti']
81 # dum['spc'] = buffer['data']['spc']
82 # dum['noise'] = buffer['data']['noise']
83 # dum.pop('data')
84 # code = dum.pop('exp_code')
85 # channel.send_group(u'{}_spc'.format(code), {'text': simplejson.dumps(dum, ignore_nan=True)})
86 # print 'Sending...{} - {} bytes'.format('spc', len(str(dum)))
68 def main():
69 print('Starting ZMQ server...')
70 while True:
71 buffer = receiver.recv_json()
72 code = update(buffer)
73 for plot in buffer['data']:
74 dum = buffer.copy()
75 dum['time'] = [buffer['time']]
76 dum[plot] = buffer['data'][plot]
77 dum.pop('data')
78 dum.pop('exp_code')
79 channel.send_group(u'{}_{}'.format(code, plot), {'text': simplejson.dumps(dum, ignore_nan=True)})
80 print('Sending...{} - {} bytes'.format(plot, len(str(dum))))
87 81
88 # dum = buffer.copy()
89 # dum['time'] = [buffer['time']]
90 # dum['noise'] = [[x] for x in buffer['data']['noise']]
91 # dum.pop('data')
92 # code = dum.pop('exp_code')
93 # channel.send_group(u'{}_noise'.format(code), {'text': simplejson.dumps(dum, ignore_nan=True)})
94 # print 'Sending...{} - {} bytes'.format('noise', len(str(dum)))
82 if __name__=='__main__':
83 loaddata()
84 main() No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now