Enviar um café pro programador

Mostrando postagens com marcador NumPy. Mostrar todas as postagens
Mostrando postagens com marcador NumPy. Mostrar todas as postagens

Gráficos em Python - Como ler arquivos, Definir tamanho dos eixos, Rótulos (labels), Cores, Tipos de linha e Legendas

 Neste tutorial de nosso curso de Programação Científica em Python, vamos continuar aprendendo como gerar gráficos em Python usando o módulo Pyplot da biblioteca Matplotlib, ferramentas nativas, gratuitas, flexíveis e extremamente poderosas da linguagem Python.

No tutorial anterior, aprendemos como plotar gráficos simples em Python, usando a função plot(). Agora, vamos aprender mais algumas técnicas e possibilidades, para incrementar nossas figuras.


Como gerar gráficos a partir de arquivos: loadtxt()

Nos exemplos do tutorial anterior, usamos apenas alguns poucos dados, mas o comum em Ciência de Dados é usar centenas, milhares e até milhões de informações, tanto para gerar gráficos como para encontrar padrões.

No exemplo a seguir, vamos usar a função loadtxt(), do NumPy, ideal para ler dados de arquivos txt de uma maneira bem simples. Basicamente, essa função recebe uma string com o endereço do arquivo de texto e o tipo de dado que queremos usar para gerar o array.

Baixe esse arquivo itub.txt e salve na mesma pasta do seu script em Python:
https://github.com/jarlissonmoreira/PythonProgressivo

Esse arquivo tem 250 colunas e duas colunas, representando os últimos 250 preços de fechamento da ação do Itaú (ITUB3), na bolsa de valores, que é minha ação favorita para receber dividendos.

Nosso código fica assim:

import matplotlib.pyplot as plt import numpy as np dados = np.loadtxt("itub.txt", float) x = dados[:, 0] y = dados[:, 1] plt.plot(x,y)

A função loadtxt() colocou esses dados em uma matriz 250 x 2.
Usamos nosso conhecimento de slicing de arrays para pegar a coluna 1 da matriz e usar como eixo x, e a coluna 2 como eixo y, para enfim usar a função plot() para gerar o gráfico de cotações:

Como gerar gráfico de cotações em Python

Definindo os limites dos eixos X e Y: xlim() e ylim()

Veja que, em todos nossos gráficos, o Python automaticamente definiu a faixa de valores que é exibida nos eixos X e Y, de maneira automática.

Porém, como tudo na programação, isso é ajustável. E para tal, vamos usar as funções xlim() e ylim(), do módulo Pyplot.

Vamos gerar um gráfico da função 2*cosseno, no intervalo de 0 até 2pi, e deixar o Pyplot setar automaticamente os valores dos eixos:

import matplotlib.pyplot as plt import numpy as np x = np.linspace(0, 2*np.pi, 1000) y = 2 * np.cos(x) plt.plot(x,y)

Como plotar gráficos em Python

Agora vamos definir o eixo x de 0 até 4pi e o eixo y de -2.5 até 2.5, veja como fica o código:

import matplotlib.pyplot as plt import numpy as np x = np.linspace(0, 2*np.pi, 1000) y = 2 * np.cos(x) plt.xlim(0, 4*np.pi) plt.ylim(-2.5, 2.5) plt.plot(x,y)

E o gráfico, como ficou mais 'de longe', pois os eixos agora são maiores:

xlim() e ylim() em gráficos Python

Ou seja, basta fornecer o intervalo de valores nas funções xlim() e ylim()


Rótulos (labels) dos eixos: xlabel() e ylabel()

Se você olhar bem, todos os gráficos em livros, artigos científicos e até na internet, possuem descrições sobre o que representa cada eixo.

São os rótulos, ou labels, e basta usarmos as funções xlabel() e ylabel() do Pyplot, fornecendo a string que você quer que seja exibida nos respectivos eixos.

Veja como fica nosso código do gráfico do cosseno:

import matplotlib.pyplot as plt import numpy as np x = np.linspace(0, 2*np.pi, 1000) y = 2 * np.cos(x) plt.xlim(0, 4*np.pi) plt.ylim(-2.5, 2.5) plt.xlabel("Ângulo x, em radianos") plt.ylabel("2*cos(x)") plt.plot(x,y) plt.show()

Nosso gráfico ficou:

Labels xlabel() e ylabel() em gráficos do Matplotlib

É sempre interessante você colocar o que é cada eixo, bem como as respectivas unidades que foi utilizado.


Plotando dois gráficos numa mesma imagem

Também é comum plotarmos duas ou mais funções em um mesmo gráfico, algo que é particularmente útil principalmente para compararmos valores, funções e padrões.

Por exemplo, no código abaixo, vamos plotar as funções seno e cosseno, com valores de x indo de 0 até 10pi:

import matplotlib.pyplot as plt import numpy as np x1 = np.linspace(0, 10*np.pi, 1000) x2 = np.linspace(0, 10*np.pi, 1000) y1 = np.cos(x1) y2 = np.sin(x2) plt.xlim(0, 10*np.pi) plt.ylim(-1.5, 1.5) plt.xlabel("Ângulo x, em radianos") plt.ylabel("cos(x) (azul) e sen(x) (em laranja)") plt.plot(x1,y1) plt.plot(x2,y2) plt.show()

Vejamos o resultado:

Como plotar várias coisas no mesmo gráfico em Python

Note que o Pyplot colocou, automaticamente, cada gráfico de uma função com uma cor diferente.

Como alterar Cores e Tipos de linhas dos gráficos

No exemplo anterior, vimos que os gráficos ficaram com as cores azul e laranja. Isso também pode ser alterado conforme seu gosto.

Se desejar que seu gráfico seja vermelho, fornece um argumento adicional na função plot(), com as string 'red' ou 'r': plot(x, y, 'r')

Se desejar que a linha seja pontilhada, ao invés de contínua, forneça a string '--':
plot(x, y, '--')

E se quiser que ela seja vermelha e pontilhada? Simples, use: 'r--'
Veja:

import matplotlib.pyplot as plt import numpy as np x = np.linspace(-2*np.pi, 2*np.pi, 1000) y = np.tan(x) plt.ylim(-2, 2) plt.xlabel("x, em rad") plt.ylabel("$tg(x)$") plt.grid() plt.plot(x,y, 'r--') plt.show()

Veja como ficou o gráfico:

Alterar cor e formato da linha no Matplotlib

Note que usamos a função grid() do Pyplot, para exibir as 'grades' (quadriculado).
As cores principais podem ser:

  • b : blue
  • g : green
  • r : red
  • c : cyan
  • m : magenta
  • y : yellow
  • k : black
  • w : white
Já os estilos de linha são:
linestyle solid dotted dashed dashdot


Você pode fornecer esses argumento da seguinte maneira: color = 'green', linestyle='dotted'
Veja como ficou o código e gráfico:

import matplotlib.pyplot as plt import numpy as np x = np.linspace(-2*np.pi, 2*np.pi, 1000) y = np.tan(x) plt.ylim(-2, 2) plt.xlabel("x, em rad") plt.ylabel("$tg(x)$") plt.grid() plt.plot(x,y, color='green', linestyle='dotted') plt.show()

Como plotar gráficos com o Pyplot

Outras possibilidades são alterar o tamanho das fontes, espessura das linhas, marcadores e estilos etc, veja:

https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html


Legendas dos gráficos: legend()

Muitas vezes é interessante fornecer informações sobre os gráficos não apenas nos eixos (labels), mas diretamente dentro do plot.

É especialmente útil quando plotamos várias funções em um imagem só. Para especificar cada gráfico do plot, colocamos o argumento label dentro de cada plot(), com a string que queremos exibir. Depois, chamamos a função legend() do pyplot:

import matplotlib.pyplot as plt import numpy as np x1 = np.linspace(0, 10, 11) x2 = np.linspace(0, 5, 11) y1 = x1 y2 = x2**2 plt.plot(x1,y1, label='Função linear y=x') plt.plot(x2,y2, label='Função quadrática y=x²') plt.legend() plt.show()

Veja o resultado:

Como inserir legendas em Python

Você pode inclusive definir onde quer que essas legendas apareçam. Por exemplo, para aparecer embaixo (lower) e no centro (center), basta colocar essas informações no argumento 'loc' da função legend():

import matplotlib.pyplot as plt import numpy as np x1 = np.linspace(0, 10, 11) x2 = np.linspace(0, 5, 11) y1 = x1 y2 = x2**2 plt.plot(x1,y1) plt.plot(x2,y2) plt.legend(['Função linear y=x', 'Função quadrática y=x²'], loc='lower center') plt.show()

Veja não usamos os argumentos label dentro das funções plot(). Ao invés disso, passamos uma lista com as strings, uma para cada plot, diretamente na função legend, e em seguida usamos o loc para dar a localização desejada da legenda.

Para ver mais variações e possibilidades, acesse:

https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.legend.html


Exercício de programação científica

Mostramos exemplos de gráficos seno, cosseno e tangente. Porém, o NumPy não tem, nativamente, as funções secante, cossecante e cotagente. Ou seja, você vai ter que implementar elas. Lembra das aulas de trigonometria?

Gere um gráfico, com intervalo de -2pi até +2pi, plotando essas três funções, com as cores vermelhas, verde e azul, respectivamente.

Exercícios de Arrays e Matrizes em Python

 Agora que já estudamos arrays, vamos praticar nossos conhecimentos na biblioteca numpy e praticar com exercícios. Estude antes:

E mais uma vez vamos reforçar: tente. Tente resolver as questões, sozinho, pense, quebre a cabeça...normal errar, não conseguir, faz parte. Mas tem que tentar, só assim você vai evoluir, tanto como programador Python tanto como cientista.

Questões de Array e Matriz

00. Qual a relação matemática entre len(arr), len(arr[0]) e  o atributo size?

01. Crie uma função sum() que recebe um array unidimensional e retorna a soma de seus elementos, usando apenas o atributo size do NumPy.

02. Crie uma função square_matrix(), que verifica se a matriz recebida é quadrada ou não. Matriz quadrada é aquela que o número de linhas é o mesmo do de colunas.

03. Crie uma função chamada trace() que recebe uma matriz quadrada e retorna o seu traço, ou seja, a soma dos elementos da diagonal principal. Lembrando que somente matrizes quadradas possuem traço.

04. Crie uma função sum_matrix() que recebe duas matrizes e retorne uma matriz com a soma destas duas matrizes anteriores. Lembre-se que só podemos somar matrizes que tenham mesmo número de linhas e colunas, seu script deve checar isso antes de somar.


Soluções e código comentado dos exercícios

  • Questão 00

O comando len(arr) vai mostrar quantos elementos tem o array. Se ele for um array unidimensional, ele vai mostrar quantos elementos tem naquele array. Se for uma matriz, ele vai mostrar o número de linhas na matriz, pois cada linha é um novo elemento (um novo array).

Por exemplo, o elemento arr[0] é a primeira linha da matriz arr, logo, o comando len(arr[0]) vai mostrar quantos elementos tem o array unidimensional arr[0], ou seja, quantas colunas esse array unidimensional tem. Mas, todas as linhas de uma matriz possuem o mesmo número de colunas. Logo, o comando len(arr[0]) exibe o número de colunas de uma matriz.

O atributo size dos arrays mostra o número TOTAL de elementos de uma matriz. Por exemplo, se tiver um array 5x6 de nome arr e usar o comando arr.size, vai ver que ele é um inteiro de valor 5*6=30

Ou seja, o size mostra o valor da multiplicação do número de linhas pelo número de colunas, então, para uma matriz: arr.size = len(arr) * len(arr[0])

  • Questão 01

O atributo size nos fornece a quantidade de elementos que existe em um array qualquer. Se esse valor é n e jogarmos esse valor dentro da função range(), ela vai iterar do elemento 0 até o elemento n-1 do array. Ou seja, vai percorrer todo o array:

import numpy as np def sum(arr): soma=0 for i in range(arr.size): soma += arr[i] return soma arr = np.array([1, 2, 3, 4, 5]) print("Soma dos elementos: ", sum(arr))

Ou seja, pegamos uma variável soma, inicializamos ela com o valor 0 e em seguida vamos adicionando elemento por elemento do array.

  • Questão 02

Vimos na questão 00 que o número de linhas do vetor arr é dado por len(arr) e o número de colunas é dado por len(arr[0]), então para saber se uma matriz é quadrada, basta verificar se esses dois valores são iguais:

import numpy as np def square_matrix(arr): if len(arr) == len(arr[0]): return True else: return False arr1 = np.array([ [1,2,3], [4,5,6], [7,8,9] ]) arr2 = np.array([ [1,2,3,4],[1,2,3,4] ]) print(square_matrix(arr1)) print(square_matrix(arr2))


  • Questão 03

Primeiro, antes de calcular o traço da matriz, precisamos saber se ela é quadrada, portanto vamos deixar o código da função square_matrix() da questão anterior neste caso. Então, a primeira coisa da função trace() é checar se a função é quadrada. Se for, calcula o traço no teste condicional if, se não for, retorna None no else.

Os elementos da diagonal principal de uma matriz arr são arr[0][0], arr[1][1], arr[2][2]...ou seja, todos os elementos do tipo arr[i][i], de mesmo índice de linha e coluna.

Então, o traço é dado pela soma: arr[0][0] + arr[1][1] + arr[2][2] + ... + arr[n-1][n-1] , onde n é a ordem da matriz, ou seja, o número de linhas ou colunas (já que ela é quadrada).

Para fazer esse cálculo no código Python, definimos uma variável de valor inicial 0 e vamos somando os elementos da diagonal inicial de índice 0 até n-1, através da range():

import numpy as np def square_matrix(arr): if len(arr) == len(arr[0]): return True else: return False def trace(arr): sum=0 if square_matrix(arr): for i in range(len(arr)): sum += arr[i][i] return sum else: return None arr1 = np.array([ [0,2,3], [4,5,6], [7,8,9] ]) arr2 = np.array([ [1,2,3,4], [1,2,3,4] ]) print(trace(arr1)) print(trace(arr2))


  • Questão 04

.A primeira coisa que a função deve fazer é testar se o número de linhas são iguais e o número de colunas também são iguais entre si. Somente assim podemos somar as duas matrizes.

Se ambas matrizes tiverem o mesmo número de linhas lin=len(arr) e o mesmo número de colunas col=len(arr[0]), então criamos uma matriz vazia (empty), com tal tamanho.

Agora, basta preencher os elementos da matriz. Para isso, usamos um laço for de 0 até lin-1 e outro laço aninhado, de 0 até col-1, então para cada elemento matrix[lin][col] colocamos a soma arr1[lin][col]+arr2[lin][col]

import numpy as np

def sum_matrix(arr1, arr2):
if len(arr1)==len(arr2) and len(arr1[0])==len(arr2[0]):
matrix = np.empty( (len(arr1), len(arr1[0])) )
else:
return None
for lin in range(len(arr1)):
for col in range(len(arr1[0])):
matrix[lin][col] = arr1[lin][col] + arr2[lin][col]
return matrix


arr1 = np.array([ [1,2,3],
[4,5,6],
[7,8,9],
[0,1,2]])

arr2 = np.array([ [1,1,1],
[2,2,2],
[3,3,3],
[0,0,0]])

print(sum_matrix(arr1, arr2))

Histograma em Python - Como gerar e plotar gráficos

 Neste tutorial, vamos aprender como gerar um gráfico do tipo histograma, através da linguagem de programação Python.

O que é um Histograma

Histograma é um tipo de gráfico, com barras verticais, onde cada uma represente uma classe de valores, e a altura representa a frequência que essa classe aparece no seu conjunto de dados. Numa linguagem mais técnica, representa uma distribuição de frequências.

Por exemplo, um consultório médico criou um histograma, para melhor entender a distribuição de idades dos pacientes:

Como plotar gráficos do tipo Histograma

No eixo x, temos as idades dos pacientes. Cada barra dessas representa uma idade ou intervalo de idades. Já o eixo y representa quantas vezes cada intervalo desses apareceu.

Pelo gráfico, podemos ver que cada barra dessas tem um intervalo próximo de 5 anos. A maior parte dos pacientes, tem por volta dos 20-25 anos e 25-30, pois cada barra que representa esses intervalos apareceu (frequência) mais de 50 vezes. Ou seja, tem mais de 100 pacientes com idade entre 20 e 30 anos.

Pacientes com mais de 90 anos? Bem poucos.
Pacientes com 0-5 anos de idade? Quase 20.

O gráfico do tipo histograma é muito útil quando você tem uma grande quantidade de dados e quer, rápida e facilmente, identificar como está a distribuição de determinados valores desses dados. Por ser uma maneira visual de representar e classificar dados, é muito usada para exibir resultados, seja em trabalhos científicos como em reuniões, por exemplo.

Tipos de Histograma em Python

Como podem imaginar, existe uma infinidade de tipos de gráficos histograma, e cada um deles nos diz informações muito importante sobre os dados que estamos analisando.

E, obviamente, o Python pode nos ajudar muito, mas muito mesmo, nessa tarefa de plotar e analisar.

Experimento do Pêndulo Simples

No laboratório de Física da Universidade Federal do Ceará (UFC), realizei o famoso experimento do pêndulo simples:

Pêndulo simples em Python

Cuja fórmula do período é dada por:

Física com Python

Onde L é o comprimento da corda do pêndulo, e g o valor da gravidade no local, que é 9,78 m/s² dentro do Campus do Pici, local onde foi realizado a medição.

Logo, o valor teórico do período é: T = 2,009141114 s = 2,01s
Vamos usar o mesmo número de algarismos significativos do cronômetro usado, dois.

Os valores que calculei podem ser obtidos em:
https://github.com/jarlissonmoreira/PythonProgressivo/blob/main/Histograma/data.txt

Note que os valores obtidos experimentalmente estão bem próximos do valor teórico. Vamos colocar esses valores em um histograma e ver isso em um gráfico, para confirmar que a maioria das medições estão ali por volta desse valor 2.01s

O meu arquivo tem 135 linhas, divididas em 10 colunas. Mas o script que será apresentado é bem abrangente, você pode colocar seus dados em quaisquer números de linhas e colunas, que ele vai funcionar.

Vamos aprender como usar o script para plotar um histograma.


Como plotar um Histograma em Python

Vamos usar a biblioteca matplotlib e a função hist() dela, para plotar nosso histograma.
Mas, antes, precisamos tratar nossos dados, antes de passar os valores para essa função.

De onde o script vai puxar esses dados? Onde e como você vai armazenar eles? Eles tem vírgula ou ponto, como decimal? Se for vírgula, precisa trocar por ponto. Como estão formatados? Tudo junto? Numa matriz? Em txt ou csv?

Usar as funções é fácil, o que devemos ter cuidado é na hora de tratar os dados.

No script fornecido abaixo, você pode passar os dados de várias maneiras. Eu, por exemplo, coloquei todos os dados no arquivo txt acima mencionado e em seguida usei o endereço desse arquivo "data.txt" (pois o data.txt está na mesma pasta do script histograma.py) para o parâmetro path da minha função plot_histograma().

Se preferir, pode passar diretamente os dados através do parâmetro data (como não usei, coloquei o valor None nele), fornecendo uma string de valores. Obviamente, só é viável se tiver poucos dados.

Por fim, precisamos configurar o bins, que são os intervalos das barras, no eixo x. Eu passei o valor 'auto', para a função hist() fazer o melhor ajuste possível, mas você pode definir manualmente os intervalos que desejar.

Vamos plotar três gráficos. O primeiro, é o histograma da matriz original, com todos os dados, bastando fazer:

  • ax1.hist(array, bins)

Onde array são os dados e bins os intervalos.

No segundo gráfico, vamos calcular as médias de cada linha da matriz. Nossa matriz tem 135 linhas com 10 elementos em cada. Logo, nosso segundo gráfico vai ter 135 elementos. Isso é muito usado em Física Experimental, a média das médias, pois fornecem valores mais confiáveis e próximos do teórico, pois 'amenizam' os resultados muito discrepantes.

Por fim, ploetei os dois gráficos juntos, um na frente do outro, para vermos a diferença.

O resultado ficou:

Script para fazer histograma em Python

Nosso script, usado para gerar esses plots de histogramas, é:

import numpy as np
from matplotlib import pyplot


def plot_histograma(path: str = None, data: str = None, bins: float | str = None) -> None:
    #path: caminho do arquivo .txt com os dados "caminho/do/data.txt"
    #bins: se nao fornecido retorna o histograma dos valores individuais,
    #ele pode ser tamanho (float), ou uma string com valores: 'auto', 'fd', 'doane', 'scott', 'stone', 'rice', 'sturges', or 'sqrt'
    #return: printa na tela o histograma
    
    if path is not None:
        with open(path, "r") as file:
            content = file.read().replace(',', '.')
            values: list[float] = [float(i) for i in content.split()]
    else:
        content = data.replace(',', '.')
        values: list[float] = [float(i) for i in content.split(';')]
   
    array = np.array(values)
    
    if bins is None:
        bins=sorted(values)
       
    if type(bins) is str:
        bins=bins
       
    if type(bins) is float:
        bins = np.arange(array.min(), array.max() + bins, bins)
    
    #Transforma o array/lista de valores em uma matriz com 10 colunas
    col = 10
    lin = int(len(array)/col)
    array2 = array.reshape(lin,col)
    
    #Cria um array, onde cada elemento é uma média de 10 valores,
    #de cada linha da matriz anterior
    median=np.mean(array2, axis=1)
    
    #Novo código para imprimir os três gráficos, com mesmo eixo x
    fig, (ax1, ax2, ax3) = pyplot.subplots(3, 1, sharex=True)

    #Primeiro gráfico, de 1350 medições
    ax1.hist(array, bins)
    ax1.xaxis.set_tick_params(labelbottom=True)
    leg1 = str(lin*col)
    ax1.set_xlabel(leg1+' medições')

    #Segundo gráfico, das 135 médias
    ax2.hist(median,bins)
    ax2.xaxis.set_tick_params(labelbottom=True)
    leg2 = str(len(median))
    ax2.set_xlabel(leg2+' médias')
    
    #Sobrepondo os dois, para efeitos de comparação
    ax3.hist(array, bins, alpha=0.5, label=leg1)
    ax3.hist(median, bins, alpha=0.5, label=leg2)
    ax3.set_xlabel('Gráficos sobrepostos')
    ax3.legend(loc='upper right')
    
    pyplot.tight_layout()
    pyplot.show()

path="data.txt"
data=None
bins='auto'
plot_histograma(path,data,bins)