Graph.py 8.86 KB
Newer Older
1 2
#importação de bibliotecas
from PyQt5 import QtWidgets
Alisson Claudino's avatar
Alisson Claudino committed
3
from pyqtgraph import PlotItem,AxisItem,GridItem
4 5 6 7
import numpy as np

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#      Classe Graph baseada em pyqtgraph                                                                    #
Alisson Claudino's avatar
Alisson Claudino committed
8
#      Autor: Alisson Claudino (alisson.claudino@ufrgs.br)  -> https://lief.if.ufrgs.br/~itsalissom         #
9 10 11 12 13
#      Licença: GNU GPLv2                                                                                   #
#      Propósito: Gerar gráficos de tempo real com diversas curvas                                          #
#                                                                                                           #
#                                                                                                           #
# Observações:                                                                                              #
14 15 16
#   Os parâmetros iniciais dados são: taxa de amostragem em segundos (float), escala de tempo (float),      #
#   numero de eixos (int),valores de escala y_min e y_max (float[],float[]), dimensões do gráfico (int,int) #
#   cores das curvas (char[]), nomes das curvas (string[]). e unidades das curvas (string[])                #
17
#                                                                                                           #
18 19 20
#                                                                                                           #
#   Para a função updateData, é dado um float[] de mesmo tamanho que o número de curvas para que todas      #
#   possam ser atualizadas corretamente                                                                     #
21 22 23 24 25 26 27 28
#                                                                                                           #
#   O atributo index é utilizado para controle do tamanho dos vetores com valores de x e y de gráfico       #
#                                                                                                           #
#   x_range e x_sampling são os valores para visualização do eixo x e amostragem. Eles definem o tamanho    #
#   que os arrays devem ter para ter uma correta sincronia da visualização de gráfico e da amostragem.      #
#                                                                                                           #
#   Os arrays precisam manter-se com os mesmos tamanhos, e devem ter tamanhos limitados para não            #
#   consumir muita memória.                                                                                 #
29 30 31 32 33 34
#                                                                                                           #
#   Como para ambas as curvas pode ser setada somente uma escala, para fazer com que cada uma possua        #
#   sua própria escala, o plot tem uma escala definida pelo maior e menor valor de escala das curvas        #
#   e então cada valor dado possui um offset e um fator de correção para correta visualização dos dados     #
#   na tela.                                                                                                #
#                                                                                                           #
35 36 37 38 39
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #


class Graph(PlotItem):      #Herança de pyqtgraph.PlotItem

40
    index = 0           #Valor de índice para controle de tamanho dos arrays
41
    
42
    warningFlag = False
43 44 45

    def __init__(self,x_sampling, x_range, n_axis, y_min, y_max, x_size, y_size, color, name,unit):  #Construtor da classe
        super(Graph, self).__init__()  #Instanciamento do construtor da classe mãe
46 47
        self.offset = []
        self.correctFactor = []
48
        self.n_axis=n_axis
49
        for n in range(0,n_axis):
50 51 52 53 54 55 56 57 58
            self.offset.append(y_min[n]-min(y_min))
            self.correctFactor.append((max(y_max)-min(y_min))/(y_max[n]-y_min[n]))
        print(n)
        print(" ")
        print(self.offset)
        print(" ")
        print(self.correctFactor)
        print("\n\n")

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
        self.x_range = x_range/x_sampling  #Correção de escala coerente com a amostragem
        self.curve = []                    #Declaração do array de curvas
        self.axis = []                     #Declaração do array de eixos
        self.y=[]                          #Declaração da matriz de valores das curvas

        self.curve.append(self.plot(pen=color[0], name=name[0]))  #Plotagem da primeira curva
        self.axis.append(AxisItem("left",color[0]))               #Primeiro eixo fica à esquerda do gráfico
        self.axis[0].setLabel(name[0], unit[0])                   #Configuração do primeiro eixo com seu nome e sua respectiva unidade
        self.axis[0].setRange(y_min[0], y_max[0])                 #Configuração do primeiro eixo com seu respectivo range
        y_axis = np.array([])                                     #Plotagem de array vazio para base do array de valores de y
        self.y.append(y_axis)                                     #Adição dos array de valores da primeira curva vazio



        for n in range(1,n_axis): #Repetição do ultimo grupo de comandos, porém aplicando-se a todos os eixos e curvas consecutivos
            self.curve.append(self.plot(pen=color[n], name=name[n]))
            self.axis.append(AxisItem("right",color[n]))
            self.axis[n].setLabel(name[n],unit[n])
            self.axis[n].setRange(y_min[n],y_max[n])
            self.y.append(y_axis)

        self.axisTime = AxisItem("bottom", 'w')     #Declaração do eixo de tempo
        self.axisTime.setLabel("Tempo", 's')        #Configuração do eixo de tempo com seu nome e unidade
        self.axisTime.setRange(0, x_range)          #Configuração da escala do eixo de tempo
        self.setXRange(0, self.x_range, padding=0)  #Configuração da escala de tempo no gráfico
        self.x=[]                               #Declaração do array de valores de tempo vazio

        self.showAxis("left", False)            #Desativação dos eixos convencionais do gráfico
88
        self.showAxis("bottom", False)
89
        self.setMinimumSize(x_size, y_size)     #Fixação do tamanho do gráfico
90

91
        self.setYRange(min(y_min), max(y_max), padding=0)   #Configuração da escala Y real do gráfico (Cada curva deve se adequar à sua respectiva escala)
Alisson Claudino's avatar
Alisson Claudino committed
92
        self.showGrid(255,255,1)
93

94
    def updateGraph(self, y):
Alisson Claudino's avatar
Alisson Claudino committed
95
        self.axis[1].setGrid(255)
96
        y_dim=len(y)
97
        if(y_dim<self.n_axis and self.warningFlag==False):    #Emissão de aviso caso hajam menos dados que curvas
98 99 100 101 102 103 104
            error = QtWidgets.QMessageBox()
            error.setText("Array enviado possui %(a)d valores, necessário no mínimo %(b)d valores. Os %(c)dº primeiros gráficos "
                          "serão setados com os valores recebidos a partir de então" % {"a":len(y),"b":int(self.n_axis),"c":len(y)})
            error.setWindowTitle("Aviso: Dados recebidos menor que o número de curvas")
            error.exec()
            self.warningFlag = True

105
        if(y_dim>self.n_axis and self.warningFlag==False):    #Emissão de aviso caso hajam mais dados que curvas
106 107 108 109 110 111 112 113 114 115
            error = QtWidgets.QMessageBox()
            error.setText("Array enviado possui %(a)d valores, necessário no máximo %(b)d valores. Os gráficos serão atualizados "
                          "com os %(c)d primeiros valores recebidos" % {"a":len(y),"b":int(self.n_axis),"c":int(self.n_axis)})
            error.setWindowTitle("Aviso: Dados recebidos maior que o número de curvas")
            error.exec()
            self.warningFlag=True
            y_dim=self.n_axis


        for n in range(0,y_dim):
Alisson Claudino's avatar
Alisson Claudino committed
116
            try:
117
                self.y[n] = np.append(self.y[n], (float(y[n])-self.offset[n])* self.correctFactor[n])  # Cada valor contido no array y vai para seu respectivo array com sua respectiva escala
Alisson Claudino's avatar
Alisson Claudino committed
118 119 120 121

            except ValueError:
                print("ERROR")

122 123
        for n in range(0, y_dim):                    #Quando o mesmo chega no valor máximo (definido pela escala+amostragem)
            if len(self.y[n]) > self.x_range+1:                #Tamanho do array de tempo deve ser igual ao de cada curva
124
                self.y[n] = np.delete(self.y[n], 0)      #O valor de índice 0 é removido para que um novo valor possa entrar no maior indice
125 126
                self.index = self.x_range                #Valor de índice quando chega no máximo, é mantido nele
            elif n==0:
Alisson Claudino's avatar
Alisson Claudino committed
127
                self.x.append(self.index)                     #Se o tamanho do array ainda não chegou ao seu máximo, então valores vão sendo adicionados no array de tempo
128

129
        for n in range(0, y_dim):
130
            self.curve[n].setData(self.x,self.y[n])       #Replotagem das curvas com valores atualizados
Alisson Claudino's avatar
Alisson Claudino committed
131
        self.index += 1                                   #Valor de índice é aumentado