I'm doing a program in Python 2.7.15 to display the data of various temperature sensors in real time by serial communication with the Arduino. However, the chart showed some unwanted problems that I broke my mind trying to solve, but no solution. The y-axis does not show temperature values, while the x-axis shows the time values correctly, and the legend is duplicated. Here is the code:
#Importando bibliotecas
import serial #Importando biblioteca pyserial
import matplotlib.pyplot as plt #Importando biblioteca para gerar graficos
import matplotlib.ticker as ticker #Importando biblioteca para configuracao dos eixos
import math #Importando biblioteca matematica
import warnings #Importando biblioteca de avisos
import time #Importando biblioteca de funções de tempo
import drawnow #Importando biblioteca para gráficos animados
#Inicializando variáveis globais
temp = [] #Lista para armazenar dados de temperatura
Time = [] #Lista para armazenar dados de tempo
soma=0 #Conta o número de termopares enviados
tempomedida = 0 #Guarda o tempo de comunicação serial
xinf = 0 #Limite inferior do eixo do tempo
xsup = 0 #Limite superior do eixo do tempo num determinado momento
yinf = 0 #Limite inferior do eixo da temperatura
ysup = 0 #Limite superior do eixo da temperatura num determinado momento
#Definindo parâmetros para comunicação serial
gate = "COM3"
baud_rate = 115200
#Definindo o objeto para comunicação com o arduino
serial = serial.Serial(gate, baud_rate)
#Abrindo arquivo para salvar dados
ComunicArquivo = open('sensortermopar.dat', 'w')
plt.ion() #Chamando gráfico interativo
#--------------------------------------------------------------------------------------------------------------------------------------------
#Programa
#Definindo função para entrada de dados
def EntradaDeDados():
#Chamando variáveis globais
global soma, tempomedida
#Variáveis locais inicializadas
n,j,tempomedida=0,0,0
aux=1
listat = []
#Pede um número de termopares
print "Termopares em uso: "
while (n<1)or(n>14):
string = str(raw_input(""))
serial.write(string)
n = ord(string)-48
time.sleep(0.5)
#Pede os termopares para exibir
print "Termopares a monitorar (Mande um de cada vez. Quando terminar, mande o valor 0):"
while (aux!=0)and(soma<n): #Enquanto o valor 0 não for enviado ou todos os termopares não forem enviados, esse bloco é executado.
strt=' ' #A variável strt é "apagada" sempre que esse bloco for executado
strt = str(raw_input("")) #O dado serial é armazenado na variável strt
serial.write(strt)
t = ord(strt) - 48 #Transformando char num inteiro
if t>=0: #Se t for maior ou igual a zero,
#Verifica se o termopar já foi colocado
if t==0: #se o valor enviado for 0,
if j==0: #e se ele for o primeiro valor,
#um aviso aparece na tela,
print "Deve enviar pelo menos um termopar!"
time.sleep(0.5)
#e a mensagem pedindo termopares aparece novamente.
print "Termopares a monitorar (Mande um de cada vez. Quando terminar, mande o valor 0):"
else: #Caso não for o primeiro valor,
#um aviso de encerramento aparece na tela.
print "\nPronto!\n"
aux = t #e o valor é armazenado numa variável auxiliar.
else: #Caso outro valor for enviado,
if t<=n: #Se esse valor for menor ou igual ao número de termopares,
listat.append(t) #o valor é armazenado em vetort
k=0 #e a variável k é zerada.
if j==0: #e se ele for o primeiro enviado
#o termopar enviado aparece na tela,
print "> Termopar", t
soma+=1 #a variável soma é incrementada
else: #Se não for o primeiro dado enviado,
#verifica se o termopar já foi enviado antes.
for i in range(j):
if listat[i]==t: #Caso o termopar for encontrado no vetort numa posição i,
print "Termopar já colocado! Digite outro valor.\n" #um aviso aparece na tela.
break #e para de verificar.
else: #Cada vez que não for encontrado,
k+=1 #a variável k é incrementada.
if k==j: #Se k for igual a j,
#o termopar aparece na tela,
print "> Termopar", t
soma+=1 #a variável soma é incrementada.
j+=1 #a variável j é incrementada cada vez que um valor entre 0 e n for dado.
else:
print "Não há termopar", t
if(soma==n): #Se a variável soma for igual ao número de termopares,
#um aviso aparece.
print("\n")
print("Pronto! Todos os termopares enviados!\n")
print("Digite um tempo de medicao em segundos: ")
while (tempomedida<1):
tempomedida = float(raw_input(""))
time.sleep(0.5)
print("\nExibindo...\n\n")
#Definindo função para configurar gráfico
def ConfigGrafico():
#Chamando variáveis globais
global soma
ax = plt.subplot() #Definindo objeto ax para definição dos eixos
#Inserindo contorno ao gráfico
ax.spines['right'].set(color='black', linewidth=0.5) #Direita
ax.spines['top'].set(color='black', linewidth=0.5) #Topo
ax.spines['left'].set(color='black', linewidth=1.5) #Esquerda
ax.spines['bottom'].set(color='black', linewidth=1.5) #Embaixo
#Definindo tamanho da fonte da escala dos eixos
plt.xticks(fontsize=7) #Eixo x
plt.yticks(fontsize=7) #Eixo y
#Inserindo título ao gráfico e legenda aos eixos
if soma==1:
title=u'Gráfico para o termopar'
else:
title=u'Gráfico para os ' + str(soma) + ' termopares'
ax.set_title(title) #Inserindo título ao gráfico
ax.set_xlabel('Tempo(s)', color='blue', fontsize=10) #Eixo x
ax.set_ylabel('Temperatura($^{\circ}$C)', color='blue', fontsize=10) #Eixo y
#Ignorando mensagem "GUI is implemented"
warnings.filterwarnings("ignore",".*GUI is implemented.*")
#Retornando ax
return ax
#-------------------------------------------------------------------------------------------------------------------------------------------
#Definindo função para plotar gráfico
def PlotGrafico():
#Chamando variáveis globais
global soma, xinf, xsup, yinf, ysup, temp, Time
ax = plt.subplot() #Definindo objeto ax para definição dos eixos
#Inserindo limites dos eixos
ax.set_xlim(xinf, xsup)
ax.set_ylim(yinf, ysup)
#Definindo espaçamento da escala do eixo x
MajorMultipleLocatorx = (xsup - xinf)/10.0
MinorMultipleLocatorx = (xsup - xinf)/20.0
#Definindo espaçamento da escala do eixo y
MajorMultipleLocatory = (ysup - yinf)/10.0
MinorMultipleLocatory = (ysup - yinf)/20.0
#Configurando eixos
ax.xaxis.set(ticks_position='bottom', major_locator = ticker.MultipleLocator(MajorMultipleLocatorx), minor_locator = ticker.MultipleLocator(MinorMultipleLocatorx))
#Eixo x
ax.yaxis.set(ticks_position='left', major_locator = ticker.MultipleLocator(MajorMultipleLocatory), minor_locator = ticker.MultipleLocator(MinorMultipleLocatory))
#Eixo y
#Adicionando barra de erro ao eixo x e plotando grafico
for i in range(soma):
if i==0:
marker='o' #círculo
markerfacecolor='b' #marcador azul
ecolor='b' #barra de erro azul
elif i==1:
marker='^' #triângulo com ponta para baixo
markerfacecolor='g' #marcador verde
ecolor='g' #barra de erro verde
elif i==2:
marker='s' #quadrado
markerfacecolor='r' #marcador vermelho
ecolor='r' #barra de erro vermelha
elif i==3:
marker='p' #pentágono
markerfacecolor='c' #marcador ciano
ecolor='c' #barra de erro ciana
elif i==4:
marker='h' #hexágono
markerfacecolor='m' #marcador magenta
ecolor='m' #barra de erro magenta
elif i==5:
marker='*' #estrela
markerfacecolor='y' #marcador amarelo
ecolor='y' #barra de erro amarela
elif i==6:
marker='+' #sinal de adição
markerfacecolor='k' #marcador preto
ecolor='k' #barra de erro preta
elif i==7:
marker='x' #letra x
markerfacecolor='w' #marcador branco
ecolor='w' #barra de erro branca
elif i==8:
marker='D' #diamante
markerfacecolor='b' #marcador azul
ecolor='b' #barra de erro azul
elif i==9:
marker='v' #triângulo com ponta para cima
markerfacecolor='g' #marcador verde
ecolor='g' #barra de erro verde
elif i==10:
marker='<' #triângulo com ponta para esquerda
markerfacecolor='r' #marcador vermelho
ecolor='r' #barra de erro vermelha
elif i==11:
marker='>' #triângulo com ponta para direita
markerfacecolor='c' #marcador ciano
ecolor='c' #barra de erro ciana
elif i==12:
marker='_' #linha horizontal
markerfacecolor='m' #marcador magenta
ecolor='m' #barra de erro magenta
elif i==13:
marker='|' #vertical
markerfacecolor='y' #marcador amarelo
ecolor='y' #barra de erro amarela
ax.errorbar(Time, temp[i::soma], xerr=0, fmt='None', yerr=0.25, ecolor='r')
ax.plot(Time, temp[i::soma], marker, markerfacecolor, ms=5, label='Termopar ' + str(i+1), linewidth=0.0)
#Inserindo legenda
ax.legend(loc='upper right', prop={'size':9})
#-------------------------------------------------------------------------------------------------------------------------------------------
#Definindo função para comunicar com a porta serial do arduino
def LeituraSerial():
#Chamando variáveis globais
global xinf, xsup, yinf, ysup, tempomedida
#Inicializando variáveis locais
rangetime = 60 #Definindo intervalo de tempo para o eixo x
temp_min = 0 #Armazena o menor valor de temperatura até um determinado momento
temp_max = 0 #Armazena o maior valor de temperatura até um determinado momento
while True: #Loop infinito
#Definindo variáveis locais do laço while
arquivo_string = '' #Serve para guardar os dados na lista
aux = 0 #Serve para contar um "nan" na lista de dados
i = 0 #Serve para iterar o vetor de dados no bloco while
#Quando algum dado for recebido:
arduino_string = serial.readline() #Lendo a porta serial
#Gerando uma lista de strings de arduino_string
DataList = arduino_string.split(' ')
#As linhas sem dados são ignoradas
if DataList[0]!='Termopar':
continue
#Removendo elementos irrelevantes da lista DataList
while i<len(DataList):
if DataList[i] == 'Termopar':
del(DataList[i])
del(DataList[i])
elif DataList[i] == '\xc2\xbaC,':
del(DataList[i])
elif DataList[i] == 'tempo:':
del(DataList[i])
else: i+=1
DataList[len(DataList)-1] = DataList[len(DataList)-1][0:len(DataList[len(DataList)-1])-3]
#Ignorando dados indesejados
for i in range(len(DataList)-1):
if DataList[i]=='nan':
aux+=1
if aux==0: estado = True
else: estado=False
if estado==False:
continue
for i in range(len(DataList)):
DataList[i] = float(DataList[i]) #Convertendo todos os dados de DataList para tipo float
if i<len(DataList)-1: #Se i variar até o penúltimo elemento,
temperatura = DataList[i]
temp.append(temperatura) #a temperatura é armazenada na lista temp.
else: #Se i for o último elemento,
tempo = DataList[i]
Time.append(tempo) #o valor é adicionado na lista Time.
#Criando a string para escrever no arquivo
if (round(temperatura,1)==temperatura): #Se um valor tiver uma casa decimal, é acrescentado o zero na frente
arquivo_string = arquivo_string + str(temperatura) + '0' + ' '
else: #Caso contrário, continua da mesma forma
arquivo_string = arquivo_string + str(temperatura) + ' '
arquivo_string = str(tempo) + " " + arquivo_string + '\n'
ComunicArquivo.write(arquivo_string)
#Encontrando o maior e o menor valor da temperatura dos sensores para definir os limites do eixo y
for i in range(len(temp)):
cont_temp_min = 0 #Serve para encontrar o menor valor de temperatura até um determinado momento
cont_temp_max = 0 #Serve para encontrar o maior valor de temperatura até um determinado momento
for j in range(len(temp)):
if j!=i:
if temp[i]<=temp[j]:
cont_temp_min+=1
if temp[i]>=temp[j]:
cont_temp_max+=1
if cont_temp_min==len(temp)-1:
temp_min = temp[i]
if cont_temp_max==len(temp)-1:
temp_max = temp[i]
#Definindo limites do eixo x
xinf = 0 #O valor inferior é zero
if tempo<=60:
xsup = rangetime
else: #O valor superior varia a partir de 60 s
xsup = tempo
#Definindo limites do eixo y
yinf = 0 #O valor inferior está 10% abaixo da temperatura mínima
ysup = 100 #O valor superior está 10% acima da temperatura máxima
drawnow.drawnow(PlotGrafico) #Chamando drawnow para atualizar o gráfico interativo
#Quando o tempo limite de medição é atingido, a conexão com o arduino e com o arquivo é encerrada
if tempo==tempomedida:
ComunicArquivo.close()
serial.close()
plt.close()
print "\nEncerrado"
break
#-------------------------------------------------------------------------------------------------------------------------------------------
EntradaDeDados() #Chamando função EntradaDeDados1
ConfigGrafico() ##Chamando função
LeituraSerial() #Chamando função LeituraSerial
Image of the chart: