forked from AVANTUFMG/avantufmg.github.io
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprojeto.html
553 lines (475 loc) · 30.2 KB
/
projeto.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
<!DOCTYPE html>
<!--[if IE 8]> <html lang="en" class="ie8"> <![endif]-->
<!--[if IE 9]> <html lang="en" class="ie9"> <![endif]-->
<!--[if !IE]><!--> <html lang="en"> <!--<![endif]-->
<head>
<title>Projeto de PC</title>
<!-- Meta -->
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<link rel="shortcut icon" href="favicon2.ico">
<link href='http://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css'>
<!-- Global CSS -->
<link rel="stylesheet" href="assets/plugins/bootstrap/css/bootstrap.min.css">
<!-- Plugins CSS -->
<link rel="stylesheet" href="assets/plugins/font-awesome/css/font-awesome.css">
<link rel="stylesheet" href="assets/plugins/prism/prism.css">
<link rel="stylesheet" href="assets/plugins/elegant_font/css/style.css">
<!-- Theme CSS -->
<link id="theme-style" rel="stylesheet" href="assets/css/styles.css">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body class="body-green">
<div class="page-wrapper">
<!-- ******Header****** -->
<header id="header" class="header">
<div class="container">
<div class="branding">
<h1 class="logo">
<a href="index.html">
<span aria-hidden="true" class="icon_documents_alt icon"></span>
<span class="text-highlight"></span><span class="text-bold">Trabalho Prático de Programação de Computadores </span>
</a>
</h1>
</div><!--//branding-->
<ol class="breadcrumb">
<li><a href="">Home</a></li>
<li class="active">Quick Start</li>
</ol>
</div><!--//container-->
</header><!--//header-->
<div class="doc-wrapper">
<div class="container">
<div id="doc-header" class="doc-header text-center">
<h1 class="doc-title"><i class="icon fa fa-paper-plane"></i> Dashboard para dados de Voo</h1>
<div class="meta"><i class="fa fa-clock-o"></i> Última atualização: 24/06/2018<br>
Caio Tácito Borges da Costa<br>
Évany Rebeca de Freitas Guimarães</div>
</div><!--//doc-header-->
<div class="doc-body">
<div class="doc-content">
<div class="content-inner">
<section id="download-section" class="doc-section">
<h2 class="section-title">O projeto</h2>
<div class="section-block">
<p>Este projeto tem como objetivo desenvolver um programa para a aquisição e visualização interativa dos dados de telemetria do voo de uma aeronave. Os parâmetros são baseados em uma aeronave autônoma não tripulada de pequeno porte, porém o projeto pode ser facilmente modificado para operar em outras aeronaves e até mesmo em modelos comerciais. Portanto, essa documentação pode ser considerada um exemplo específico de aplicação deste projeto.
</p>
</div>
</section><!--//doc-section-->
<section id="installation-section" class="doc-section">
<h2 class="section-title">Aquisição de Dados</h2>
<div id="step1" class="section-block">
<h3 class="block-title">O computador embarcado</h3>
<p>O computador de bordo da aeronave, além de inúmeras outras funções, recebe os dados dos sensores e é responsável por organizá-los e publicá-los em um intervalo de tempo determinado. A comunicação com a estação solo pode ser estabelecida através de inúmeras combinações de rádio e protocolos. Para simplificar os testes, assumiremos uma conexão WiFi entre os computadores
</p>
<div class="code-block">
<h6>Raspberry Pi 3 B+:</h6>
<a href="#" target="_blank"><img class="img-responsive" src="assets/images/bbb.jpg" alt="bbb" /></a>
<br>
<p>Rodando Linux ARM Debian 9.0.4, o computador RPi recebe os dados de sensores através das GPIOs e das portas seriais, e usa um servidor LAMP (Linux, Apache, MySQL e PHP) para publicar os valores em um arquivo JSON.
</p>
</div><!--//code-block-->
</div><!--//section-block-->
<div id="step2" class="section-block">
<h3 class="block-title">A estação solo (computador cliente)</h3>
<p>O computador cliente, conectado na mesma rede WiFi do computador de bordo, receberá o arquivo JSON usando os módulos <b>urrlib2</b> e <b>json</b>. Qualquer modificação no arquivo será lida pelo script e carregada no programa automaticamente
</p>
<div id="javascript" class="section-block">
<div class="code-block">
<pre><code class="language-javascript">
//Exemplo JSON
{
"altitude": 3.1415,
"ground_speed": -120,
"airspeed": -22,
"climb_rate": -14,
"bat_voltage": 13,
"eng_temp": -51,
"bat_current": -14,
"engine_rpm": -22,
"time" : "1700",
"server" : "Linux 3.8 - 4.9",
"ip" : "192.168.0.249"
}
</code></pre>
</div><!--//code-block-->
</div><!--//section-block-->
<div id="step3" class="section-block">
<h6 class="block-title">Pré-processamento: </h6>
<p>Após a aquisição dos dados sem formatação, ocorrerá o seu processamento inicial para separar as diversas informações (altitude, combustível, velocidade, etc.) e guardá-las em estruturas de dados apropriadas. Haverá também a verificação das timestamps envolvidas na conexão para garantir a relevância dos dados e indicar possíveis falhas ou desconexões.
</p>
</div><!--//section-block-->
<div id="step3" class="section-block">
<h6 class="block-title">O código: </h6>
<p>O pré-processamento dos dados é feito no arquivo python "update.py":
<div id="python" class="section-block">
<div class="code-block">
<pre><code class="language-python">
#update.py
import urllib.request;
import json;
import time;
last = 0;
response = urllib.request.urlopen('http://192.168.0.249/dados.json'); #Busca o arquivo dados.json no servidor
html = response.read(); #Lê o arquivo e armazena em uma variável
parsed = json.loads(html); #Usa o módulo json para criar um dicionário contendo as chaves e os valores
# O código abaixo cria um arquivo para cada variável, salva o valor com o tempo em milissegundos,
# fecha o arquivo e imprime o resultado na saída padrão
while(1): #loop principal
if(parsed['time']==last): #Evita dados repetidos
continue;
f = open("data/altitude","a+");
f.write(str(parsed['time']+","+str(parsed['altitude']))+"\n");
f.close();
print(str(parsed['time'])+":"+str(parsed['altitude']));
f = open("data/ground_speed","a+");
f.write(str(parsed['time']+","+str(parsed['ground_speed']))+"\n");
f.close();
print(str(parsed['time'])+":"+str(parsed['ground_speed']));
f = open("data/airspeed","a+");
f.write(str(parsed['time']+","+str(parsed['airspeed']))+"\n");
f.close();
print(str(parsed['time'])+":"+str(parsed['airspeed']));
f = open("data/climb_rate","a+");
f.write(str(parsed['time']+","+str(parsed['climb_rate']))+"\n");
f.close();
print(str(parsed['time'])+":"+str(parsed['climb_rate']));
f = open("data/bat_voltage","a+");
f.write(str(parsed['time']+","+str(parsed['bat_voltage']))+"\n");
f.close();
print(str(parsed['time'])+":"+str(parsed['bat_voltage']));
f = open("data/eng_temp","a+");
f.write(str(parsed['time']+","+str(parsed['eng_temp']))+"\n");
f.close();
print(str(parsed['time'])+":"+str(parsed['eng_temp']));
f = open("data/bat_current","a+");
f.write(str(parsed['time']+","+str(parsed['bat_current']))+"\n");
f.close();
print(str(parsed['time'])+":"+str(parsed['bat_current']));
f = open("data/engine_rpm","a+");
f.write(str(parsed['time']+","+str(parsed['engine_rpm']))+"\n");
f.close();
print(str(parsed['time'])+":"+str(parsed['engine_rpm']));
f = open("data/server","w+");
f.write(str(parsed['server'])+"\n");
f.close();
print(str(parsed['server']));
f = open("data/ip","w+");
f.write(str(parsed['ip'])+"\n");
f.close();
print(str(parsed['ip']));
last = parsed['time'];
time.sleep(0.50);
</code></pre>
</div><!--//code-block-->
</p>
</div><!--//section-block-->
</section><!--//doc-section-->
<section id="dash" class="doc-section">
<h2 class="section-title">O Dashboard</h2>
<div id="s" class="section-block">
<p>O Dashboard para visualização dos dados no computador cliente foi desenvolvido usando Python3 para lidar com o processamento e GTK3+ (Pygobject) para a interface gráfica. Após pesquisar as inúmeras opções para a construção de UI em Python3, concluiu-se que a implementação Glade era a melhor alternativa, pois apresenta certas vantagens desejáveis para esse projeto, como:
<div class="row">
<div class="col-md-6 col-sm-6 col-xs-12">
<ul class="list">
<li>Permite a separação entre o código do programa (arquivo .py) e os elementos gráficos (arquivo .xml)</li>
<li>Deixa ambos os códigos mais limpos e simples.</li>
<li>Permite a implementação rápida de diversas interfaces para um mesmo programa (Temas diferentes, sistemas operacionais distintos)
</li>
<li>Usa um ambiente visual para construir a UI, no estilo "What you see is what you get", acelerando o processo de desenvolvimento e testes.</li>
</ul>
</div>
</div>
</p>
<div id="base" class="section-block">
<h3 class="block-title">Código base Python</h3>
<p>O gráficos foram gerados usando o módulo matplotlib, e a função animate para realizar as atualizações em um intervalo de tempo especificado. O código foi baseado nos tutoriais de python disponíveis <a href="https://matplotlib.org/api/animation_api.html">neste link</a></p>
<p>Inicialmente, desenvolveu-se um programa para gerar um gráfico numa Gtk.ScrolledWindow, e depois foi utilizado o Gerador para replicar este programa para os 8 gráficos. Mais informações sobre o Gerador podem ser encontradas no fim desta seção.</p>
<p>Com o intuito de evitar repetições desnecessárias, nesta documentação será apresentado o código para construir um gráfico: </p>
<div id="python" class="section-block">
<div class="code-block">
<pre><code class="language-python">
#projeto.py
import gi #Importanto PyGOobject
gi.require_version('Gtk', '3.0') #Selecionando a versão correta do GTK
from gi.repository import Gtk #Importando o GTK3
#Importando o FigureCanvas do matplotlib, módulo de compatiblidade com o GTK
from matplotlib.backends.backend_gtk3agg import (FigureCanvasGTK3Agg as FigureCanvas)
from matplotlib.figure import Figure #Importando Figure
import matplotlib.pyplot as plt #Importando pyplot
import matplotlib.animation as animation #Importando o módulo de animações do matplotlib
import numpy as np #importando numpy
from time import gmtime, strftime #Funções para o relógio
scale = 40; #Variável que determina o número de valores no eixo X dos gráficos que permanece na tela
def animate0(i): # Função que cuida da animação
relogio.set_text(strftime("%H:%M:%S", gmtime())); # Atualiza o relógio
graph_data0 = open('data/altitude','r').read(); #Abre o arquivo gerado pelo update.py
lines0 = graph_data0.split('\n'); #Cria uma lista com os pares ordenados x,y
xs0 = []; #Cria uma lista vazia para receber os valores do eixo X
ys0 = []; #Cria uma lista vazia para receber os valores do eixo Y
for line in lines0: #Itera por todas as linhas do arquivo de entrada
if len(line) > 1: #Caso a linha não esteja em branco
x, y = line.split(','); #Separa o par x,y e guarda em suas respectivas variáveis
if(len(xs0)>scale): # Verifica se o tamanho da lista é maior que a variável de escala
xs0.pop(0); # Caso seja, deleta o primeiro elemento das listas com x e y
ys0.pop(0); # Isso causa um efeito de "movimento" do gráfico e mantém a consistência dos intervalos
xs0.append(float(x)); #Adiciona x ao final da lista xs
ys0.append(float(y)); #Adiciona x ao final da lista xs
ax0.clear(); #limpa o subplot
ax0.plot(xs0, ys0); #plota novamente com as infromações atualizadas
builder = Gtk.Builder(); #Cria uma instância do Gtk.builder()
builder.add_from_file("GUI.glade"); #Adiciona o arquivo da interface gráfica
handlers = { #Dicionário com os sinais da interface gráfica
"onDestroy": Gtk.main_quit, #Sinal do botão de sair do menu
"on_window1_destroy": Gtk.main_quit, #Sinal do botão de fechar a janela
};
builder.connect_signals(handlers); #Passa o dicionário de sinais como argumento para o builder
sw0 = builder.get_object('janela0'); #Seleciona a Gtk.ScrolledWindow "janela0" da interface gráfica
f0 = plt.figure(); #Cria uma plt.figure() para desenhar o gráfico
ax0 = f0.add_subplot(1,1,1); #Adiciona um subplot único à figura criada
#Cores:
ax0.set_facecolor('#31363b');
f0.patch.set_facecolor('#31363b');
ax0.spines['bottom'].set_color('#eff0f1');
ax0.spines['top'].set_color('#eff0f1');
ax0.spines['right'].set_color('#eff0f1');
ax0.spines['left'].set_color('#eff0f1');
ax0.tick_params(axis='x', colors='#eff0f1');
ax0.tick_params(axis='y', colors='#eff0f1');
canvas0 = FigureCanvas(f0); #Cria uma área de desenho do GTK
ani0 = animation.FuncAnimation(f0, animate0, interval=500); #Inicia a animação com um intervalo de 500 milissegundos
canvas0.set_size_request(300, 200); #Seleciona o tamanho mínimo da área de desenho
sw0.add_with_viewport(canvas0); #Adiciona o desenho à "janela0"
server = open('data/server','r').read(); #Lê o nome do servidor
ip = open('data/ip','r').read(); #Lê o IP do servidor
slabel = builder.get_object('server'); #Seleciona o label do servidor
slabel.set_name('server'); #Dá um nome
slabel.set_text("\n"+server); #Escreve o valor lido no label
ilabel = builder.get_object('ip'); #Seleciona o label do ip
ilabel.set_name('ip'); #Dá um nome
ilabel.set_text("\n"+ip); #Escreve o valor lido no label
ilabel.set_size_request(10,10);
window = builder.get_object("window1"); #Seleciona a janela principal da interface gráfica
window.show_all(); #Mostra a janela principal
def gtk_style(): #Função de estilos CSS
css = b"""
* {
transition-property: color, background-color, border-color, background-image, padding, border-width;
transition-duration: 1s;
font-family: Cantarell;
font-size: 22px;
}
window {
background-color: #232629;
color: #232629;
}
label#relogio {
font-size: 20px;
background-color: #31363b;
color: #ffffff;
}
label#server {
font-size: 20px;
background-color: #31363b;
color: #ffffff;
}
label#ip {
font-size: 20px;
background-color: #31363b;
color: #ffffff;
}
label#logo {
font-size: 20px;
background-color: #31363b;
color: #ffffff;
}
"""
style_provider = Gtk.CssProvider()
style_provider.load_from_data(css)
Gtk.StyleContext.add_provider_for_screen(
Gdk.Screen.get_default(),
style_provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
)
gtk_style()
Gtk.main(); # Função principal do GTK
</code></pre>
</div><!--//code-block-->
<p>Ao executar o código acima, temos um gráfico gerado na janela0 da GUI:</p>
<a href="assets/images/screen1.png" target="_blank"><img class="img-responsive" src="assets/images/screen1.png" alt="screen1" /></a>
<p>Após usar o Gerador para multiplicar o código, são criados os 8 gráficos:</p>
<a href="assets/images/screen2.png" target="_blank"><img class="img-responsive" src="assets/images/screen2.png" alt="screen2" /></a>
</div><!--//section-block-->
</div>
<div id="xml" class="section-block">
<h3 class="block-title">Código XML (Glade GTK3+)</h3>
<p>A interface gráfica foi desenhada usando a ferramenta open source Glade, que gera o arquivo XML utilizado pelo código base:</p>
<a href="assets/images/screen3.png" target="_blank"><img class="img-responsive" src="assets/images/screen3.png" alt="screen3" /></a>
<br>
<p>O Design tem o objetivo de ser o mais simples possível, permitindo que a atenção do usuário seja voltada para o conteúdo da aplicação e não para a interface em si. Por ser extremamente comum em computadores "mainstream" atuais, adotou-se a resolução 1366x768 como padrão, porém alguns cuidados foram tomados para que a aplicação se comporte adequadamente em resoluções superiores. Utilizou-se a <a href="https://community.kde.org/KDE_Visual_Design_Group/HIG/Color">paleta de cores do KDE Plasma 5</a> como referência, e antes de inicar o projeto foi feito um sketch simples usando o Adobe Illustrator:</p>
<a href="assets/images/screen4.png" target="_blank"><img class="img-responsive" src="assets/images/screen4.png" alt="screen4" /></a>
<br>
<p>Em seguida, usando o sketch como referência, foi construída a GUI. A versão final ficou organizada da seguinte forma:</p>
<a href="assets/images/screen5.png" target="_blank"><img class="img-responsive" src="assets/images/screen5.png" alt="screen5" /></a>
<br>
<p>Feito isso, basta executar o arquivo projeto.py e o programa será iniciado:</p>
<a href="assets/images/screen6.png" target="_blank"><img class="img-responsive" src="assets/images/screen6.png" alt="screen6" /></a>
<br>
</div><!--//section-block-->
</div>
<div id="rdm" class="section-block">
<h3 class="block-title">Exemplo de operação com valores aleatórios</h3>
</div>
<p>Um programa python simples pode ser executado no servidor para testar o programa com valores aleatórios:</p>
<div class="code-block">
<pre><code class="language-python">
#aleatorio.py
import time;
import random;
scale = 1000
for i in range(0,scale):
f = open("dados.json","w+");
f.write("{\n");
f.write("\"altitude\":%d,\n" % random.randint(0,100));
f.write("\"ground_speed\": %d,\n" % random.randint(0,100));
f.write("\"airspeed\": %d,\n" % random.randint(0,1000));
f.write("\"climb_rate\": %d,\n" % random.randint(0,10));
f.write("\"bat_voltage\": %d,\n" % random.randint(0,48));
f.write("\"eng_temp\": %d,\n" % random.randint(0,200));
f.write("\"bat_current\": %d,\n" %random.randint(0,90));
f.write("\"engine_rpm\": %d,\n" %random.randint(0,23000));
f.write("\"time\" :\"%d\" ,\n" % i);
f.write("\"server\" : \"Linux 3.8 - 4.9\",\n");
f.write("\"ip\" : \"192.168.0.249\"\n");
f.write("}");
f.flush();
f.close();
print(i);
time.sleep(1);
</code></pre>
</div><!--//code-block-->
<p>Foi gravado um vídeo curto demonstrando o funcionamento do programa. O terminal do monitor da direita está conectado via ssh a um servidor e roda o arquivo de geração de números aleatórios, enquanto o Dashboard roda no monitor central.</p>
<div>
<h6></h6>
<!-- 16:9 aspect ratio -->
<div class="embed-responsive embed-responsive-16by9">
<iframe class="embed-responsive-item" src="assets/images/video_low.mp4" frameborder="0" allowfullscreen></iframe>
</div>
</div>
<section id="gerador" class="doc-section">
<h2 class="section-title">Gerador</h2>
<div id="gerador" class="section-block">
<p>Devido ao grande número de partes do código repetidas, foi criado um código auxiliar no jupyter notebook para auxiliar na programação do código principal:</p>
<div class="code-block">
<pre><code class="language-python">
#update.py
l = ['altitude','ground_speed','airspeed','climb_rate','bat_voltage','eng_temp','bat_current','engine_rpm'];
for i in range(0,len(l)):
print("f = open(\"data/%s\",\"a+\");" % l[i]);
print("f.write(str(parsed['time']+\",\"+str(parsed['%s']))+\"\\n\");" % l[i]);
print("f.close();");
print("print(str(parsed['time'])+\":\"+str(parsed['%s']));" % l[i]);
print()
</code></pre>
</div><!--//code-block-->
<div class="code-block">
<pre><code class="language-python">
#funções de animação
colors = ["#c9ce3b","#11d116","#2ecc71","#f67400","#fdbc4b","#da4453","#1d99f3","#1cdc9a"];
for i in range(0,len(l)):
print("def animate%d(i):" % i);
print(" graph_data%d = open('data/%s','r').read();" % (i,l[i]));
print(" lines%d = graph_data%d.split('\\n');" % (i,i));
print(" xs%d = [];" % i);
print(" ys%d = [];" % i);
print(" for line in lines%d:" % i);
print(" if len(line) > 1:");
print(" x, y = line.split(',');");
print(" if(len(xs%d)>scale):" %i);
print(" xs%d.pop(0);" %i);
print(" ys%d.pop(0);" %i);
print(" xs%d.append(float(x));" %i);
print(" ys%d.append(float(y));" %i);
print(" ax%d.clear();" %i);
print(" ax%d.plot(xs%d, ys%d, \"%s\");" %(i,i,i,colors[i]));
</code></pre>
</div><!--//code-block-->
<div class="code-block">
<pre><code class="language-python">
#Criação dos gráficos
for i in range(0,len(l)):
print("sw%d = builder.get_object('janela%d');" % (i,i));
print("f%d = plt.figure();" %i);
print("ax%d = f%d.add_subplot(1,1,1);" % (i,i));
print("ax%d.set_facecolor('#31363b');" %i );
print("f%d.patch.set_facecolor('#31363b');" %i);
print("ax%d.spines['bottom'].set_color('#eff0f1');" %i);
print("ax%d.spines['top'].set_color('#eff0f1');" %i);
print("ax%d.spines['right'].set_color('#eff0f1');" %i);
print("ax%d.spines['left'].set_color('#eff0f1');" %i);
print("ax%d.tick_params(axis='x', colors='#eff0f1');"%i);
print("ax%d.tick_params(axis='y', colors='#eff0f1');"%i);
print("canvas%d = FigureCanvas(f%d);" % (i,i));
print("ani%d = animation.FuncAnimation(f%d, animate%d, interval=500);" % (i,i,i));
print("canvas%d.set_size_request(300, 200);" % i);
print("sw%d.add_with_viewport(canvas%d);" % (i,i));
print();
</code></pre>
</div><!--//code-block-->
</div>
</section>
</section><!--//doc-section-->
</div><!--//content-inner-->
</div><!--//doc-content-->
<div class="doc-sidebar hidden-xs">
<nav id="doc-nav">
<ul id="doc-menu" class="nav doc-menu" data-spy="affix">
<li><a class="scrollto" href="#download-section">O Projeto</a></li>
<li>
<a class="scrollto" href="#installation-section">Aquisição de dados</a>
<ul class="nav doc-sub-menu">
<li><a class="scrollto" href="#step1">Computador embarcado</a></li>
<li><a class="scrollto" href="#step2">Computador cliente</a></li>
<li><a class="scrollto" href="#step3">Código</a></li>
</ul><!--//nav-->
</li>
<li>
<a class="scrollto" href="#dash">Dashboard</a>
<ul class="nav doc-sub-menu">
<li><a class="scrollto" href="#base">Base</a></li>
<li><a class="scrollto" href="#xml">XML</a></li>
<li><a class="scrollto" href="#rdm">Testes</a></li>
</ul><!--//nav-->
</li>
<li><a class="scrollto" href="#gerador">Gerador</a></li>
</ul><!--//doc-menu-->
</nav>
</div><!--//doc-sidebar-->
</div><!--//doc-body-->
</div><!--//container-->
</div><!--//doc-wrapper-->
</div><!--//page-wrapper-->
<footer id="footer" class="footer text-center">
<div class="container">
<!--/* This template is released under the Creative Commons Attribution 3.0 License. Please keep the attribution link below when using for your own project. Thank you for your support. :) If you'd like to use the template without the attribution, you can check out other license options via our website: themes.3rdwavemedia.com */-->
<small class="copyright">Docs written by CaioTBC - <a href="http://programaacao.net.br/" targe="_blank">IFMG Campus Ouro Preto</a> | </small>
<small class="copyright">Designed with <i class="fa fa-heart"></i> by <a href="http://themes.3rdwavemedia.com/" targe="_blank">Xiaoying Riley</a> for developers</small>
<br>
</div><!--//container-->
</footer><!--//footer-->
<!-- Main Javascript -->
<script type="text/javascript" src="assets/plugins/jquery-1.12.3.min.js"></script>
<script type="text/javascript" src="assets/plugins/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="assets/plugins/prism/prism.js"></script>
<script type="text/javascript" src="assets/plugins/jquery-scrollTo/jquery.scrollTo.min.js"></script>
<script type="text/javascript" src="assets/plugins/jquery-match-height/jquery.matchHeight-min.js"></script>
<script type="text/javascript" src="assets/js/main.js"></script>
</body>
</html>