PDF Python Completo
PDF Python Completo
Este material foi fornecido como complemento ao curso de Python do Iniciante ao Avançado. Contém vários complementos das aulas do
curso.
Desenvolvido e escrito por Gabriel Hasmann.
github.com/gfreire57
https://www.linkedin.com/in/gabriel-hasmann/
Módulo 1
Parte 1 - Básico de programação e da linguagem
Introdução
O que são variáveis?
Variáveis em Python são espaços físicos de memória utilizados para armazenar dados.
Quando você cria uma variável, está basicamente reservando espaço na memória do computador para armazenar valores. Esses valores
podem ser de diversos tipos, seja um número inteiro, um número com casas decimais, caracteres, palavras e por ai vai.
Em algumas linguagens, você precisa declarar explicitamente o tipo do dado que você quer armazenar quando você cria a variável.
Entretanto, em Python, você não precisa fazer isso, por isso ela é conhecida como uma linguagem "dinamicamente tipada". Ou seja, o tipo
da variável é inferido pelo valor que ela recebe automaticamente. Por isso é importante ficar esperto com quais informações você está
salvando.
1. Inteiros ( int ): Representam números inteiros, positivos ou negativos, sem parte decimal. Ao
Exemplo: idade = 30
2. Ponto flutuante ( float ): Representam números reais, ou seja, com parte decimal, positivos ou negativos. Como a maioria das
linguagens, o separador decimal em Python é o ponto ao invés da vírgula.
Exemplo: altura = 1.75
3. Strings ( str ): Sequências de caracteres, utilizadas para representar texto.
Exemplo: nome = "Maria"
4. Booleanos ( bool ): Possuem dois valores possíveis: True (verdadeiro) ou False (falso).
Exemplo: estudante = True
# Dica do futuro: para verificar o tipo de uma variável, podemos usar a função `type(variavel)`. Exemplo:
> idade = 10
> type(idade)
>>> <class 'int'>
1. Listas ( list ): Coleções ordenadas e mutáveis de itens, que podem ser de um tipo ou de tipos diferentes
Exemplo:
numeros = [1, 2, 3, 4, 5]
numeros = [1, 1.5, 'esse é um texto', True, 5]
2. Tuplas ( tuple ): Coleções ordenadas e imutáveis de itens, que podem ser de tipos diferentes.
Exemplo: coordenadas = (10.0, 20.0)
3. Dicionários ( dict ): Coleções desordenadas de pares chave-valor.
Exemplo: pessoa = {"nome": "João", "idade": 25}
4. Conjuntos ( set ): Coleções desordenadas de itens únicos.
Exemplo: cores = {"vermelho", "azul", "verde"}
3. Principais operadores na linguagem
1. Aritméticos
O operador de divisão sempre retorna uma número do tipo float, mesmo se a divisão retornar um valor inteiro.
> print(4 / 2)
>>> 2.0 # Tipo <float>, e não <int>
2. Comparação
Esses operadores sempre retornam um valor booleano (True ou False). Os operadores de igualdade e de diferença pode ser feita entre
variáveis de diferente tipos, como abaixo, onde o inteiro 2 é comparado com a string "2":
>>> 2 == "2"
False
Os outros operadores retornam erros (ou Exceptions) de tipo, dados por TypeError.
3. Operadores de atribuição
4. Lógicos
Os operadores lógicos são muito usados em estruturas condicionais, como if .
Strings
Strings em Python podem ser criadas simplesmente ao colocar texto entre aspas simples ( '...' ) ou aspas duplas ( "..." ). Aspas triplas
( '''...''' ou """...""" ) permitem criar strings que abrangem várias linhas.
Indexação: Você pode acessar um caractere individual em uma string usando sua posição (índice), começando do zero.
s = "Python"
print(s[0]) # Saída: P
Pode-se também utilizar indices negativos, os quais começam do fim para o início. Veja o exemplo abaixo:
strip() : Para remover espaços em branco (ou outros caracteres) do início e do fim de uma string.
split() : Para dividir uma string em uma lista de strings com base em um delimitador.
join() : Para concatenar uma lista de strings em uma única string, usando uma string como separador.
print(",".join(['a', 'b', 'c'])) # Saída: a,b,c
find() e index() : Para encontrar a posição de uma substring dentro de uma string. find() retorna -1 se a substring não for
encontrada, enquanto index() lança uma exceção.
print("Python".find("th")) # Saída: 2
Formatação de Strings
Python oferece várias maneiras de formatar strings:
Operador % : Um método antigo, inspirado na linguagem C. Não o recomendo pois as opções seguintes são melhores.
Método format() : Mais flexível e intuitivo do que o operador % .
F-strings (Literal String Interpolation): Introduzido no Python 3.6, permite incorporar expressões dentro de strings prefixando a string
com f .
nome = "Mundo"
print(f"Olá, {nome}!") # Saída: Olá, Mundo!`
Listas
Criação de Listas
Para criar uma lista, utiliza-se os colchetes para delimitar os elementos que pertencerão à lista. Os elementos são separados por vírgulas.
Por exemplo:
minha_lista = [1, 2, 3, 4, 5]
Acesso a Elementos
Os colchetes são usados para acessar elementos específicos de uma lista através de seus índices. Os índices em Python começam em 0,
então o primeiro elemento de uma lista está no índice 0, o segundo no índice 1, e assim por diante.
Aqui o uso de índices negativos também é permitido, seguindo a mesma lógica aplicada em strings visto anteriormente (o elemento de
índice -1 é o último, -2 o penúltimo e continua.)
Fatiamento (Slicing)
Os colchetes também são usados para fazer o fatiamento de listas, permitindo acessar subconjuntos de seus elementos. Para isso, utiliza-
se a notação [início:fim] , onde início é o índice do primeiro elemento do subconjunto e fim é o índice que marca o fim do subconjunto
(o elemento neste índice não é incluído).
sublista = minha_lista[1:] # Retorna [2, 3, 4, 5] pois pegamos do segundo elemento (posição 1) até o último
sublista = minha_lista[:2] # Retorna [1, 2] pois pegamos o primeiro elemento até o elemento na posição 1, já que o indice 2
não é incluído.
Modificação de Elementos
Para modificar um elemento específico em uma lista, usa-se colchetes para acessar o elemento pelo índice e então atribuir um novo valor.
minha_lista[0] = 10
print(minha_lista) # [10, 2, 3, 4, 5]
Embora a adição e remoção de elementos geralmente envolvam métodos específicos como append() , insert() , pop() , e remove() vistos
logo no tópico seguinte, pode-se usar os colchetes para operações como a substituição de subconjuntos de elementos ou a limpeza da
lista.
Métodos úteis
list.append(x)
Adiciona um item ao final da lista. Equivalente a a[len(a):] = [x] .
list.extend(list2)
Estende a lista anexando todos os itens do iterável list2 . Ou seja, concatena os valores de list2 à list
list.insert(i, x)
Insere um item em uma posição dada. O primeiro argumento é o índice do elemento antes do qual inserir, então a.insert(0, x)
insere no início da lista, e a.insert(len(a), x) é equivalente a a.append(x) .
list.remove(x)
Remove o primeiro item da lista cujo valor é igual a x. Ele dá um erro do tipo ValueError se não houver tal item.
list.pop([i])
Remove o item na posição dada na lista e o retorna. Se nenhum índice for especificado, a.pop() remove e retorna o último item
da lista. Ele levanta um IndexError se a lista estiver vazia ou o índice estiver fora do alcance da lista.
list.clear()
Remove todos os itens da lista. Equivalente a del a[:] .
list.index(x[, start[, end]])
Retorna o índice baseado em zero na lista do primeiro item cujo valor é igual a x. Levanta um ValueError se não houver tal item.
Os argumentos opcionais start e end são interpretados como na notação de fatiamento e são usados para limitar a busca a uma
subsequência particular da lista. O índice retornado é calculado relativo ao início da sequência completa, em vez do argumento
start.
list.count(x)
Retorna o número de vezes que x aparece na lista.
list.sort(*, key=None, reverse=False)
Ordena os itens da lista (os argumentos podem ser usados para personalização da ordenação, onde key pode receber uma
função (lambda, por exemplo), e reverse inverte a ordem da lista se True ).
list.reverse()
Inverte os elementos da lista.
list.copy()
Retorna uma cópia rasa da lista. Equivalente a a[:] .
Packing e unpacking
Packing ocorre quando atribuímos vários valores a uma única variável, e Python automaticamente os empacota em uma tupla.
Exemplo de Packing:
tupla = 1, 2, 3
print(tupla) # Saída: (1, 2, 3)
(a, b, c) = tupla
print(a) # Saída: 1
print(b) # Saída: 2
print(c) # Saída: 3
Sets
Um set (conjunto) em Python é uma coleção desordenada de itens únicos. Sets são usados para armazenar múltiplos itens em uma única
variável, semelhante a listas e tuplas, porém, enquanto listas e dicionários podem conter elementos duplicados, um set não pode. Sets são
particularmente úteis para eliminar itens duplicados de uma sequência e para realizar operações matemáticas de conjuntos, como união,
interseção, diferença, e diferença simétrica.
Características:
Desordenados: Os itens não são armazenados em nenhuma ordem específica e não são indexados.
Mutáveis: Podem ser alterados após sua criação, mas os itens armazenados devem ser imutáveis.
Não aceitam duplicatas: Cada elemento em um set é único.
Sintaxe: Os sets são definidos por chaves {} , com itens separados por vírgulas, como meu_set = {1, 2, 3} . Para criar um set vazio,
deve-se usar set() , pois {} cria um dicionário vazio.
set1.union(set2) # {1, 2, 3, 4, 5}
set1.intersection(set2) # {3}
set1.difference(set2) # {1, 2}
set1.symmetric_difference(set2) # {1, 2, 4, 5}
Estruturas condicionais
if
A declaração if é a estrutura condicional mais básica em Python. Ela testa uma condição e executa um bloco de código se a condição for
verdadeira.
if condição:
# execute este bloco de código
else
A declaração else complementa if , executando um bloco de código quando a condição testada por if é falsa.
if condição:
# execute este bloco se a condição for verdadeira
else:
# execute este bloco se a condição for falsa
elif
elif , uma abreviação de "else if", permite testar múltiplas condições em sequência. Se a condição de um if ou elif anterior for falsa, o
Python testa a condição seguinte em um elif .
if condição1:
# execute este bloco se condição1 for verdadeira
elif condição2:
# execute este bloco se condição2 for verdadeira
else:
# execute este bloco se todas as condições anteriores forem falsas
Exemplos
Uso de if, else, e elif
idade = 20
if idade < 18:
print("Menor de idade")
elif idade >= 18 and idade < 60:
print("Adulto")
else:
print("Idoso")
# "Adulto"
Estruturas de loop
for
O laço for é usado para iterar sobre uma sequência (como uma lista, tupla, dicionário, conjunto ou string) e executar um bloco de código
para cada item.
while
O laço while continua a executar um bloco de código enquanto uma condição for verdadeira.
while condição:
# execute este bloco enquanto a condição for verdadeira
Laços Aninhados (Nested Loops)
Laços aninhados ocorrem quando um laço é colocado dentro de outro. Eles são úteis para operações que requerem iteração através de
múltiplas dimensões ou conjuntos de dados.
Exemplos
# Olá, Ana!
# Olá, Bruno!
# Olá, Carlos!
contador = 5
while contador > 0:
print(contador)
contador -= 1
# 5
# 4
# 3
# 2
# 1
Laços Aninhados
# outro exemplo
cores = ["vermelho", "verde", "azul"]
itens = ["carro", "bola", "lápis"]
for cor in itens:
for item in cores:
print(f"{cor} {item}")
# carro vermelho
# carro verde
# carro azul
# bola vermelho
# bola verde
# bola azul
# lápis vermelho
# lápis verde
# lápis azul
Funções
Uma função é um bloco de código que só é executado quando chamado. Python já vem com muitas funções integradas, como print() ,
mas também permite a criação de funções definidas pelo usuário (UDFs).
As funções podem receber dados para processar (conhecidos como parâmetros) e podem retornar dados como resultado. A definição de
uma função em Python é feita usando a palavra-chave def , seguida do nome da função, parênteses e dois pontos. O código dentro da
função deve ser indentado.
def minha_funcao():
print("Olá, do minha_funcao!")
Funções podem receber argumentos, que são utilizados para passar dados para dentro da função.
def cumprimentar(nome):
print(f"Olá, {nome}!")
resultado = somar(5, 3)
print(resultado)
# 8
Referências
https://docs.python.org/3/contents.html
https://docs.python.org/3/tutorial/introduction.html#
https://www.programiz.com/python-programming/methods/string/split
https://docs.python.org/3/tutorial/inputoutput.html
https://realpython.com/python-f-strings/
https://realpython.com/python-lists-tuples/
https://docs.python.org/3/tutorial/datastructures.html
https://www.markdownguide.org/basic-syntax/
https://www.markdownguide.org/extended-syntax/
https://docs.python.org/3/tutorial/controlflow.html#tut-docstrings
Módulo 2
List comprehension
É uma forma de criar listas e inserir operações de uma maneira simples e em uma única linha. Permite, então, aplicar fórmulas e operações
para alterar seus elementos de maneira iterativa, ou seja, a cada elemento da lista original.
Uma compreensão de listas consiste de uma expressão dentro de colchetes que contém uma expressão seguida de um for e zero ou
mais operações for ou if . O resultado é uma nova lista com seus elementos avaliados pela expressão contida dentro desses colchetes.
Veja os exemplos abaixo:
Exemplo 1
Exemplo 2
Exemplo 3
Exemplo 4
divisiveis_por_2_e_3 = []
for x in range(1, 21):
if x % 2 == 0 and x % 3 == 0:
divisiveis_por_2_e_3.append(x)
print(divisiveis_por_2_e_3)
# [6, 12, 18]
# Mostrar todas as combinações entre elementos de duas listas se eles não forem iguais
combs = []
for x in [1,2,3]:
for y in [3,1,4]:
if x != y:
combs.append((x, y))
print(combs)
# [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
Dict comprehension
É o equivalente de list comprehension porém aplicado para dicionários. Dict comprehension é escrito entre chaves e necessita de duas
expressões separadas por : , onde a primeira é relacionada à chave do dicionário e a segunda ao valor daquela chave, seguidas por for, if
ou a combinação entre uma ou mais for/ifs. Veja os exemplos abaixo.
Exemplo 1
Exemplo 2
Exemplo 3
Exemplo 4
Exemplo 5
1. os
O módulo os fornece uma maneira fácil de usar funcionalidades dependentes do sistema operacional, como ler ou escrever arquivos,
manipular caminhos, etc.
Exemplo 1: Listar os arquivos em um diretório.
# abaixo, no lugar de '.', pode-se colocar um caminho para uma pasta do seu computador, listando todas as pastas e arquivos
contidos nesse diretório.
# um exemplo de diretório: "C:\Users\gabri\OneDrive\Área de Trabalho"
# OBS: sempre coloque uma letra 'r' antes da string do diretório para o python interpretar o \ de maneira literal. Sem o 'r',
o \ é usado para caracteres especiais.
import os
print(os.listdir(r'C:\Users\gabri\OneDrive\Área de Trabalho'))
# usando esse comando
import os
print(os.getlogin())
# gabri # ( nome do meu usuário no meu computador )
import os
caminho = 'exemplo.txt'
if os.path.exists(caminho):
print(f"O arquivo ou diretório '{caminho}' existe.")
else:
print(f"O arquivo ou diretório '{caminho}' não existe.")
2. math
O módulo math oferece acesso a funções matemáticas definidas pelo padrão C.
Exemplo 1: Calcular a raiz quadrada de um número.
import math
print(math.sqrt(16))
# 4.0
import math
print(math.cos(math.pi))
# -1.0
3. datetime
O módulo datetime fornece classes para manipulação de datas e horas.
Exemplo 1: Obter a data e hora atuais.
4. time
O módulo time oferece funções para trabalhar com tempo, incluindo funções para pausas e para obter o tempo atual.
Exemplo 1: Esperar por um determinado número de segundos.
import time
time.sleep(5)
import time
print(time.time())
5. getpass
O módulo getpass é utilizado para solicitar ao usuário uma senha sem exibi-la na tela.
Exemplo 1: Solicitar uma senha (semelhante à função input mas o no campo de escrita o texto é substituído por *)
import getpass
senha = getpass.getpass('Digite sua senha: ')
import getpass
getpass.getuser()
# gabri
Quando o python é instalado, muitos módulos já são pré-carregados. O link a seguir contém todos os módulos com suas descrições que
você pode usar sem precisar instalar mais nada.
Módulos pré-instalados em Python
pip --version
Atualizando o pip
É uma boa prática manter o pip atualizado. Para atualizá-lo, execute no prompt de comando:
# Linux/macOS
pip install --upgrade pip
# Windows
python -m pip install --upgrade pip
Funções lambda
As funções lambda em Python são uma ferramenta poderosa e concisa, permitindo a criação de funções anônimas em uma única linha de
código. Estas funções são chamadas de "anônimas" porque não precisam ser definidas com um nome como as funções regulares definidas
com a palavra-chave def . As funções lambda são úteis em muitas situações, especialmente quando se trabalha com operações que
requerem uma função como argumento, como as funções de ordem superior map() , filter() , e reduce() . Neste artigo, vamos explorar o
conceito de funções lambda e ver vários exemplos de como elas podem ser utilizadas.
Uma função lambda em Python é definida pela palavra-chave lambda , seguida por uma lista de argumentos, dois pontos e a expressão que
a função deve executar. A expressão é avaliada e retornada quando a função é chamada. A sintaxe geral de uma função lambda é:
add = lambda x, y: x + y
print(add(5, 3))
# 8
Podemos chamar uma função lambda sem atribuir a uma variável, passando os argumentos em uma tupla à direita da expressão lambda
entre parêntesis (aqui os argumentos são posicionais, então a ordem importa):
(lambda x, y: x + y)(5, 3)
# 8
Exemplo 2: Passar strings de uma lista para maiúsculo (sem e com condições).
Aqui, a função map() aplica a função lambda a cada um dos itens contidos na lista ["maçã", "banana", "cereja", "damasco"]
Aqui, estamos filtrando a lista ['maçã', 'banana', 'cereja', 'damasco'] retornando os elementos que contém a letra 'e'.
filter(*função*, *sequencia*) -> onde podemos passar uma função (definida por def ou *lambda*, por exemplo), e uma
sequencia ou iterador (como listas e chaves de dicionários).
Ela, por padrão, retorna um objeto filter. Esse objeto pode ser aplicado a funções como list() para gerar uma lista ou set() para gerar um
set.
Exemplo 2: Combinar Elementos de Duas Listas. Aqui, somamos o n-ésimo elemento da lista 1 com o n-ésimo elemento da lista 2. Nesse
caso, como colocamos 2 argumentos na função lambda (x e y), precisamos passar 2 argumentos (lista1 e lista2) na função map() .
lista1 = [1, 2, 3]
lista2 = [4, 5, 6]
combinados = list(map(lambda x, y: x + y, lista1, lista2))
print(combinados)
# [5, 7, 9]
resultado = 10 / 0
Caso isso ocorresse no meio de um script maior, esse erro iria fazer todo o script parar imediatamente. Muitas vezes, não queremos isso, e
para termos mais controle, usamos try e except .
try:
resultado = 10 / 0
except ZeroDivisionError:
print("Não é possível dividir por zero.")
# Não é possível dividir por zero.
Neste exemplo, a tentativa (try) de divisão por zero gera uma exceção ZeroDivisionError , que é capturada e tratada pelo bloco except ,
evitando assim que o programa falhe. Nesse caso, o programa encerra normalmente.
Caso não soubermos qual tipo de exceção irá ocorrer, podemos escrever de maneira mais genérica usando a classe "Exception", que é a
superclasse para a maioria das exceções embutidas. Faz-se isso assim:
Uso de else
O bloco else é opcional e, se presente, deve seguir os blocos try e except . Ele é executado se o bloco try não gerar uma exceção.
Exemplo 2: Uso de else
try:
resultado = 10 / 5
except ZeroDivisionError:
print("Não é possível dividir por zero.")
else:
print("Resultado:", resultado)
# Resultado: 2.0
Aqui, como a divisão é bem-sucedida, o bloco else é executado, imprimindo o resultado da operação.
Uso de finally
O bloco finally é executado após a conclusão dos blocos try , except (e opcionalmente else ), independentemente de uma exceção ter
sido lançada ou não. É ideal para realizar tarefas de limpeza, como fechar arquivos ou liberar recursos externos.
arquivo = None
try:
arquivo = open("sensores_temperatura.txt", "r")
print("O arquivo foi aberto com sucesso.")
except FileNotFoundError: # Tipo de erro quando o arquivo não foi encontrado
print("O arquivo não foi encontrado.")
finally:
if arquivo: # Se arquivo não for encontrado, continuará igual a None e não entrará nesse if
arquivo.close()
print("O arquivo foi fechado.")
# O arquivo não foi encontrado.
raise e assert
Além dos blocos try , except , else , e finally para tratamento de exceções, Python fornece duas outras palavras-chave importantes
para o controle de erros: raise e assert . Esses comandos são usados para criar exceções de maneira controlada e realizar verificações
de sanidade em seu código, respectivamente. Eles são ferramentas cruciais para garantir a correção e a robustez dos programas.
raise
Suponha que você esteja escrevendo uma função que processa transações. Se uma transação for inválida e crítica, você pode querer
interromper o script de análise e alertar o chamador sobre o problema.
def processar_transacao(transacao_eh_valida):
if not transacao_eh_valida:
raise ValueError("Transação inválida.")
# Processamento da transação
processar_transacao(None)
>>> ------------------------------------
>>> ValueError Traceback (most recent call last)
>>> 1 def processar_transacao(transacao_eh_valida):
>>> 2 if not transacao_eh_valida:
>>> ----> 3 raise ValueError("Transação inválida.")
>>> 4 # Processamento da transação
>>> 5 processar_transacao(None)
>>> ValueError: Transação inválida.
Assim, é possível invocar exceções de maneira controlada e personalizar de acordo com o problema que desejamos capturar. Além disso,
podemos substituir a keyword ValueError por Exception para invocarmos uma exceção mais genérica.
assert
assert é uma instrução que permite ao programador verificar se uma condição específica é verdadeira. Se a condição avaliada por assert
for False , uma exceção AssertionError será levantada. Isso é útil para realizar verificações de sanidade em seu código para garantir que
um estado inválido nunca seja alcançado, ou para verificar se uma variável possua um valor esperado. Por exemplo, podemos usar assert
antes do return de uma função para verificar se o output está correto.
A sintaxe de uma assertion é dada por:
>>> numero = 42
>>> assert numero > 0, f"é esperado que numero seja maior que zero, mas numero = {number}"
# Expressão é verdadeira
É possível colocar mais de uma expressão verificadora usando as keywords and e or. Também podemos usar in e out. Abaixo, espera-se
que valores não seja vazio e que contenha valores numéricos. Aqui, a função isinstance checa se cada variável dentro de valores é int ou
float e retorna uma lista com valores True ou False. Em seguida, a função all() verifica se todos os valores dessa lista são True, retornando
True se sim. Caso qualquer um for False, all() então retorna False.
def calcular_media(valores):
# Verifica se 'valores' não é vazio (portanto False) e todos os elementos são numéricos
assert valores and all(isinstance(x, (int, float)) for x in valores), "A lista deve conter pelo menos um valor numérico e
não pode ser vazia."
return sum(valores) / len(valores)
Existe a keyword any() que é semelhante à all() mas retorna True se qualquer uma for True.
Generators
Generators são implementados através de funções, mas ao invés de retornar um valor único, um generator é capaz de produzir uma
sequência de resultados ao longo do tempo, pausando a execução da função e retomando-a conforme necessário. Isso é alcançado com o
uso da palavra-chave yield .
Quando uma função contém pelo menos uma declaração yield , ela se torna um generator. Ao chamar a função, o código contido dentro
dela não é executado imediatamente. Em vez disso, um objeto generator é retornado. Esse objeto pode ser iterado com um loop for ou
com a função next() , que continua a execução da função até encontrar a próxima declaração yield . Isso evita executar todas as
iterações de um loop imediatamente, rodando o próximo iterador somente quando for solicitado.
Vantagens
Eficiência de Memória: Generators não armazenam todos os itens na memória de uma vez. Eles geram cada item sob demanda, o
que é especialmente útil para sequências grandes ou infinitas.
Conciso: Generators podem tornar o código mais legível e expressivo.
Reutilizável: Assim como os iteradores, os generators podem ser reutilizados em diferentes partes do programa.
Criação
Um generator pode ser criado da mesma forma que uma list comprehension, porém inserindo a expressão dentro de parêntesis.
Além disso, podem ser criados da mesma forma que funções, porém no lugar da palavra-chave return de retorno da função colocamos
yield .
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield a
a, b = b, a + b
fib_generator = fibonacci(10)
print(fib_generator)
>>> <generator object fibonacci at 0x000001DD9E4792E0>
next(fib_generator)
>>> 0
next(fib_generator)
>>> 1
next(fib_generator)
>>> 1
next(fib_generator)
>>> 2
next(fib_generator)
>>> 3
next(fib_generator)
>>> 5
next(fib_generator)
>>> 8
Pode-se iterar pelos valores de um generator usando loops também, como for .
for x in fibonacci(10):
print(x, end=', ')
>>> 0, 1, 1, 2, 3, 5, 8, 13, 21, 34,
Módulo 3
Leitura e Escrita de Arquivos de Texto em Python
Abrindo Arquivos
Para ler ou escrever em um arquivo, primeiro você precisa abri-lo usando a função embutida open() . Essa função retorna um objeto de
arquivo que fornece métodos e atributos para interagir com o conteúdo do arquivo.
f = open('meuarquivo.txt', 'r')
No exemplo acima, o arquivo meuarquivo.txt é aberto no modo de leitura ( 'r' ). Outros modos comuns incluem escrita ( 'w' ), anexar
( 'a' ), e modos que permitem atualização ( 'r+' , 'w+' , 'a+' ).
Modo Explicação
r Abre o arquivo somente para leitura. O arquivo deve existir, ou um erro será levantado.
w Abre o arquivo para escrita, criando um novo arquivo ou sobrescrevendo o existente.
a Abre o arquivo para anexar conteúdo no final, criando um novo arquivo se não existir.
r+ Abre o arquivo para leitura e escrita. O arquivo deve existir.
w+ Abre o arquivo para leitura e escrita, criando um novo arquivo ou sobrescrevendo o existente.
a+ Abre o arquivo para leitura e escrita, anexando o novo conteúdo no final.
Leitura de Arquivos
Há várias maneiras de ler o conteúdo de um arquivo:
conteudo = f.read()
print(conteudo)
for linha in f:
print(linha, end='')
linhas = f.readlines() # observe que aqui escreve-se .readlines(), com 's' no final, ao contrário de .readline() visto acima.
for linha in linhas:
print(linha, end='')
Após a leitura, sempre feche o arquivo para liberar recursos do sistema e evitar problemas (como corrupção do arquivo) usando f.close() .
Escrita em Arquivos
Para escrever em um arquivo, você deve abri-lo no modo de escrita ( 'w' ) ou anexar ( 'a' ).
f = open('meuarquivo.txt', 'w')
f.write('Hello, world!\n')
f.close()
Se o arquivo já existir e for aberto no modo de escrita, o conteúdo anterior será apagado. Se for aberto no modo de anexar, o novo
conteúdo será adicionado ao final do arquivo.
Uso do with
A instrução com a palavra-chave with simplifica o manejo de arquivos garantindo que eles sejam fechados automaticamente após a
conclusão do bloco indentado (com espaços antes da linha).
Exemplo de uso:
Vamos considerar que você tem um arquivo de texto chamado dados_sensores.txt com leituras de sensores de temperatura e o horário de
cada leitura. O arquivo pode ter o seguinte formato:
Cada linha contém um timestamp seguido pela temperatura medida naquele momento, separados por uma vírgula. Para gerar um arquivo
com dados simulados com o formato acima, podemos usar um código como o abaixo.
# Criando os dados
dados = []
for i in range(50):
# Calculando o timestamp atual
timestamp_atual = timestamp_inicial + timedelta(minutes=15*i)
# Gerando uma temperatura aleatória
temperatura = random.uniform(18.0, 28.0)
# Formatando a string de dados
linha = f"{timestamp_atual.strftime('%Y-%m-%d %H:%M:%S')}, {temperatura:.2f}\n"
dados.append(linha)
# Caminho do arquivo
caminho_arquivo = "/mnt/data/dados_sensores.txt"
caminho_arquivo
No código acima, vale destacar que o método strftime formata um dado do tipo datetime (no caso, a variável timestamp_inicial ) de
acordo com uma codificação. Mais detalhes podem ser vistos em: https://strftime.org/ e https://strftime.net/ (este último permite criar
diferentes configurações).
Agora, suponha que você queira abrir esse arquivo em Python, ler os dados, e calcular:
1. A temperatura média.
2. A temperatura máxima e mínima.
3. A variação de temperatura (diferença entre a temperatura máxima e mínima).
# Imprime os resultados
print(f"Temperatura Média: {temperatura_media:.2f}°C")
print(f"Temperatura Máxima: {temperatura_max:.2f}°C")
print(f"Temperatura Mínima: {temperatura_min:.2f}°C")
print(f"Variação de Temperatura: {variacao_temperatura:.2f}°C")
Este script primeiro inicializa duas listas para armazenar os valores de temperatura e os timestamps. Em seguida, abre o arquivo
dados_sensores.txt para leitura, percorre cada linha do arquivo, extrai o timestamp e a temperatura, converte a temperatura para um
número de ponto flutuante (float) e adiciona esses valores às listas correspondentes. Após ler todos os dados, o script calcula e imprime a
temperatura média, máxima, mínima, e a variação de temperatura.
Arquivos CSV
CSV é um formato simples e amplamente utilizado para armazenar dados tabulares, onde cada linha do arquivo representa um registro e
cada registro consiste em um ou mais campos separados por vírgulas. O módulo csv da biblioteca padrão do Python simplifica a leitura e
escrita de arquivos CSV.
import csv
import csv
dados = [['nome', 'cidade', 'idade'], ['John Doe', 'New York', 30], ['Jane Doe', 'Los Angeles', 25]]
Arquivos JSON
JSON é um formato leve para troca de dados, fácil para humanos lerem e escreverem, e fácil para máquinas parsearem e gerarem. Python
oferece suporte nativo ao JSON através do módulo json , que permite codificar e decodificar dados em JSON de maneira simples. Um
arquivo JSON é interpretado como um dicionário em Python, portanto após ser carregado em um script, ele passa a ser um.
Estrutura do JSON
O JSON é estruturado em dois tipos de estruturas básicas:
Coleções de pares nome/valor (objetos em JavaScript): No contexto do JSON, são representadas por objetos (dicionários em
Python) delimitados por chaves {} . Cada par nome/valor é separado por uma vírgula.
{
"nome": "John Doe",
"idade": 30
}
Listas ordenadas de valores (arrays em JavaScript): No JSON, são representadas por arrays (listas em Python) delimitadas por
colchetes [] . Cada valor dentro do array é separado por uma vírgula.
O Python fornece o módulo json , que permite codificar (converter dados em Python para uma string JSON) e decodificar (converter uma
string JSON para dados em Python) com facilidade.
import json
print(dados) # Saída: {'nome': 'Jane Doe', 'idade': 25, 'cidade': 'Los Angeles'}
Para ler dados JSON de um arquivo e convertê-los em um objeto Python, use json.load() :
import json
print(dados)
import json
dados = {
"nome": "John Doe",
"idade": 30,
"casado": False,
"filhos": ["Alice", "Bob"]
}
import json
O que é Pandas?
Pandas é uma biblioteca de código aberto que proporciona estruturas de dados de alta performance e fáceis de usar, além de ferramentas
de análise de dados para Python. Seu nome deriva de "panel data", um termo econômico para conjuntos de dados que incluem
observações ao longo do tempo para os mesmos indivíduos. Desenvolvido por Wes McKinney, o Pandas se tornou um componente
indispensável no kit de ferramentas de todo analista de dados que trabalha com Python.
Características Principais
Estruturas de Dados: O Pandas introduz duas novas estruturas de dados para Python: DataFrame e Series , que são construídas
sobre a biblioteca NumPy, permitindo uma manipulação de dados rápida e eficiente.
Facilidade de Manipulação: Permite limpar, transformar, modificar, agregar e pivotar dados com facilidade.
Leitura e Escrita de Dados: Fornece ferramentas para ler e escrever dados em diferentes formatos, como CSV, Excel, SQL, JSON,
entre outros.
Integração: Funciona bem com outras bibliotecas, incluindo bibliotecas de visualização de dados como Matplotlib, permitindo análises
complexas e visualizações com menos esforço.
Instalação
Para instalar o Pandas, você pode usar o pip, o gerenciador de pacotes do Python. Para isso, pesquise por "Anaconda Prompt" no Menu
Iniciar do computador e abra a opção que aparecer. Em seguida, escreva e execute o comando abaixo na janela que abrir:
Series
Uma Series, por sua vez, é uma estrutura de dados unidimensional que pode armazenar dados de qualquer tipo (inteiro, string, float,
objetos Python, etc.). É basicamente uma coluna de um DataFrame.
Criando um DataFrame
Um DataFrame é uma estrutura de dados bidimensional, semelhante a uma tabela de banco de dados ou uma planilha de Excel:
import pandas as pd
data = {
'Nome': ['Marcia', 'Joaquim', 'Lucas', 'Ester', 'Gabriel'],
'Filhos': [0, 3, 1, 1, 0],
'Cidade': ['Sao Paulo', 'Porto Alegre', 'Belo Horizonte', 'Brasília', 'Maceió'],
'Nascimento': ['2002-11-01', '1990-03-06', '1995-04-29', '2000-01-10', '1999-10-09']
}
df = pd.DataFrame(data)
print(df)
df.dtypes
# Nome object
# Filhos int64
# Cidade object
# Nascimento object
# dtype: object
Visualizando dados
Podemos querer mostrar somente as N primeiras ou últimas linhas. Para isso, usamos .head(N) e .tail(N) , respectivamente.
print(df.head(2))
print(df.tail(1))
Também existe o método .sample() que permite selecionar linhas aleatoriamente. A sintaxe básica dele é dada abaixo:
n: Número inteiro de itens a serem selecionados. Se não for possível, porque o tamanho do conjunto de dados é menor que n , e
replace=False , todos os itens serão retornados.
frac: Fração dos itens a serem selecionados. Por exemplo, frac=0.5 seleciona 50% dos itens.
replace: Booleano que indica se o mesmo item pode ser selecionado mais de uma vez. Útil para amostragem com reposição.
Exemplo:
Podemos também selecionar somente algumas colunas para visualização. Para isso, faz-se:
Estatísticas de dados
O método .describe() no Pandas é uma ferramenta poderosa para obter um resumo estatístico rápido e abrangente de um DataFrame ou
Series. Este método gera estatísticas descritivas que resumem a tendência central, dispersão e forma da distribuição dos dados, excluindo
valores NaN . É particularmente útil para análise exploratória de dados, oferecendo uma visão geral imediata das características numéricas
do dataset.
Você pode personalizar o comportamento do .describe() usando seus parâmetros opcionais. Por exemplo:
percentiles: Lista de percentis a serem incluídos no resumo. Exemplo: percentiles=[0.10, 0.40, 0.70] passa os percentis 10%,
40% e 70%. Por padrão são os percentis 25%, 50% e 75%.
include e exclude: Parâmetros para incluir ou excluir dados de tipos específicos. Recebe uma lista de dtypes (tipo de dados) ou, no
caso de include, pode receber "all" para incluir todos os dtypes.
.info()
Semelhante à .dtypes , mas retorna mais informações, como quantidade de linhas (4 entries), número de elementos não nulos (ou seja,
que não estão vazios), tipo da coluna, uso de memória e um resumo de todos os dtypes na tabela.
df['Nascimento'] = pd.to_datetime(df['Nascimento'])
Slicing de Colunas
O slicing direto de colunas não é suportado da mesma forma que o slicing de linhas. Em vez disso, usamos .loc[] ou .iloc[] para
alcançar um resultado semelhante.
O Método .loc[]
O método .loc[] é utilizado para selecionar linhas e colunas por rótulos. Ele aceita um único rótulo, uma lista de rótulos, uma fatia de
rótulos, ou uma condição booleana para realizar a seleção.
Aqui, ele está selecionando a linha cujo indice é igual a 3. Caso os índices forem outra coisa, como um texto, deveríamos colocar o texto
correspondente. Por exemplo, se alterarmos o índice para ser a coluna Nome, devemos usa "Ester" no lugar de "3".
info = df.loc['Ester']
print("Informações de Ester:\n", info, "\n")
sem_filhos = df.loc[df['Filhos'] == 0]
print("Pessoas sem filhos:\n", sem_filhos, "\n")
df['Nascimento'] = pd.to_datetime(df['Nascimento']) # antes de filtrar, é necessário converter a coluna para o tipo datetime.
Exemplo 7: pessoas com mais de um filho e que não são de Porto Alegre
O método .iloc[]
O método .iloc[] em Pandas é usado para selecionar linhas e colunas por sua posição numérica (índice inteiro), ao contrário do .loc[] ,
que seleciona por rótulos. Isso torna .iloc[] particularmente útil quando você precisa acessar elementos com base em sua posição na
estrutura de dados, sem se preocupar com os rótulos dos índices ou colunas.
Vamos revisitar o DataFrame do exemplo anterior. Diferente do .loc[] , não podemos usar condições diretas com .iloc[] porque ele não
opera com base em condições lógicas, mas sim em índices numéricos. Portanto, os exemplos a seguir demonstrarão como acessar e
manipular dados utilizando posições numéricas.
Recriando o DataFrame
import pandas as pd
data = {
'Nome': ['Marcia', 'Joaquim', 'Lucas', 'Ester', 'Gabriel'],
'Filhos': [0, 3, 1, 1, 0],
'Cidade': ['Sao Paulo', 'Porto Alegre', 'Belo Horizonte', 'Brasília', 'Maceió'],
'Nascimento': ['2002-11-01', '1990-03-06', '1995-04-29', '2000-01-10', '1999-10-09']
}
df = pd.DataFrame(data)
primeira_linha = df.iloc[0]
print("Primeira Linha:\n", primeira_linha, "\n")
ultima_linha = df.iloc[-1]
print("Última Linha:\n", ultima_linha, "\n")
Para carregar dados de um arquivo CSV para um DataFrame do Pandas, você pode usar a função pd.read_csv() :
import pandas as pd
Assim como com pd.read_csv() , a função pd.read_excel() também suporta vários parâmetros para personalizar como os dados são
lidos, como a escolha de qual aba do arquivo Excel ler ( sheet_name ), e especificação de colunas a serem parseadas ( usecols ).
Veja na referência mais opções de carregamento: https://pandas.pydata.org/docs/reference/api/pandas.read_excel.html
Exemplo de uso dos parâmetros da função
O arquivo de exemplo tem esse formato:
import pandas as pd
# Caminho para o arquivo CSV
csv_file_path = '/mnt/data/dados_exemplo.csv'
# Carregando o arquivo CSV: quero somente as colunas ID, Nome e Idade, e que o índice seja ID
df_csv = pd.read_csv(csv_file_path, usecols=['ID', 'Nome', 'Idade'], index_col='ID')
# Exibindo o DataFrame
print(df_csv)
# Exibindo o DataFrame
print(df_excel)
O Pandas suporta também outras origens de dados. Para conferir todas, veja esse link:
https://pandas.pydata.org/docs/user_guide/io.html
Usando to_csv()
O método to_csv() permite salvar um DataFrame como um arquivo CSV. Vamos ver como usar esse método com alguns parâmetros
úteis:
Parâmetros Explicados:
index: Ao definir como False , evita salvar o índice do DataFrame no arquivo CSV.
columns: Especifica um subconjunto de colunas a serem salvas.
sep: Define o separador de colunas, que neste exemplo é um ponto e vírgula ( ; ).
encoding: Especifica a codificação de caracteres do arquivo CSV, como 'utf-8' .
Usando to_excel()
Para salvar um DataFrame em um arquivo Excel, o método to_excel() é usado. Similar ao to_csv() , ele oferece vários parâmetros para
personalizar o arquivo de saída, mas para usá-lo é necessário instalar o módulo openpyxl:
Parâmetros Explicados:
Ao usar to_excel() , pode ser necessário instalar o pacote openpyxl ou xlsxwriter , dependendo da versão do Pandas e se você deseja
salvar o arquivo no formato .xlsx .
import pandas as pd
# Dados de exemplo
data = {
'Região': ['Norte', 'Sul', 'Norte', 'Leste', 'Sul', 'Norte', 'Leste', 'Leste', 'Sul', 'Norte'],
'Categoria': ['Eletrônicos', 'Móveis', 'Eletrônicos', 'Móveis', 'Eletrônicos', 'Móveis', 'Eletrônicos', 'Móveis',
'Eletrônicos', 'Móveis'],
'Vendas': [1000, 1500, 750, 1250, 1750, 900, 1000, 950, 1600, 950],
'Lucro': [300, 450, 200, 300, 500, 250, 300, 200, 480, 220]
}
df = pd.DataFrame(data)
Agrupamento de Dados
O agrupamento é uma técnica poderosa que permite agrupar dados baseados em algum critério e então aplicar uma função a cada grupo,
seja para agregação, transformação ou filtragem. O método .groupby() é usado para essa finalidade.
df.groupby(['Região'])['Vendas'].sum()
Pode-se agrupar por mais de uma coluna.
df.groupby(['Região', 'Categoria'])['Vendas'].sum()
Agregação de Dados
A agregação é o processo de combinar vários valores de dados em um valor resumido. Pandas permite realizar operações de agregação,
como soma, média, máximo e mínimo, em um DataFrame inteiro ou em grupos de dados.
Também aplicar mais de uma operação para mais de uma coluna diferente.
df.groupby('Região').agg({
'Vendas': ['min', 'max', 'mean'],
'Lucro': ['min', 'max', 'mean'],
'Categoria' : 'count'
})
Filtragem Avançada com .query() e combinação de métodos
O método .query() permite filtrar linhas de um DataFrame com base em uma expressão de consulta. Ele é particularmente útil para
realizar filtros complexos de maneira mais legível e direta do que utilizando o slicing tradicional com [ ] .
Suponha que temos um DataFrame df contendo informações sobre vendas, incluindo colunas para Vendedor , Região e Vendas .
import pandas as pd
Abaixo, usamos o mesmo exemplo para agrupar os dados por Região e somar as vendas de cada uma.
Aqui, usamos .agg para obter a soma e a média de vendas de cada região.
print(resultado)
Também podemos aplicar funções customizadas. Abaixo, aplicamos uma função que retorna a amplitude das vendas para cada grupo, que
é a diferença entre o valor máximo e mínimo das vendas.
print(resultado_amplitude)
import pandas as pd
import numpy as np
Gráfico de Linhas
Um gráfico de linhas pode ser usado para visualizar tendências de dados ao longo do tempo.
Gráfico de Barras
Gráficos de barras são úteis para comparações de categorias.
Esse comando cria um histograma para a coluna Vendas , com 5 intervalos (bins), mostrando a distribuição dos seus valores.
Para criar um gráfico de dispersão e explorar a relação entre duas variáveis, podemos usar plot com kind='scatter' e especificar as
colunas para os eixos X e Y.
Figura (Figure)
A figura é a área na qual todos os elementos do gráfico são desenhados. Ela serve como o recipiente de nível superior para todos os
elementos do gráfico.
Eixos (Axes)
Os eixos representam a área onde os dados serão plotados. Eles incluem os eixos X e Y, onde os dados são mapeados. Cada eixo possui
uma escala que define como os dados serão distribuídos.
Linhas (Lines)
As linhas representam os dados plotados no gráfico. Elas podem ser usadas para representar séries temporais, tendências ou
relacionamentos entre variáveis.
Título (Title)
O título fornece uma descrição concisa do conteúdo do gráfico. Ele ajuda a contextualizar os dados e fornece uma orientação para o leitor.
Rótulos dos Eixos (Axis Labels)
Os rótulos dos eixos são textos descritivos que indicam o que cada eixo representa. Eles fornecem informações sobre as unidades dos
dados plotados e ajudam a entender o significado dos valores representados.
Legenda (Legend)
A legenda é uma caixa de texto que descreve o significado das diferentes cores ou padrões das linhas no gráfico. Ela ajuda a identificar as
séries de dados representadas no gráfico.
Grade (Grid)
A grade é uma grade de linhas de referência que facilita a leitura e a interpretação do gráfico. Ela fornece um contexto visual para os dados
plotados.
Marcadores (Markers)
Os marcadores são símbolos utilizados para marcar pontos de dados específicos no gráfico. Eles ajudam a destacar pontos importantes e
facilitam a interpretação dos dados.
Introdução aos tipos de gráficos: linha e barras
Gráficos de Linhas
Os gráficos de linhas são úteis para visualizar dados em uma sequência ordenada e são comumente usados para representar dados ao
longo do tempo.
Suponha que você queira visualizar como a temperatura varia ao longo de um dia. Você pode ter os seguintes dados de temperatura (em
°C) registrados a cada hora:
horas = range(24)
temperaturas = [22, 21, 20, 19, 18, 18, 19, 20, 22, 24, 26, 28, 29, 30, 29, 28, 26, 25, 24, 23, 22, 22, 21, 21]
plt.plot(horas, temperaturas)
plt.title('Variação da Temperatura ao Longo do Dia')
plt.xlabel('Hora do Dia')
plt.ylabel('Temperatura (°C)')
plt.grid(True)
plt.show()
plt.figure(figsize=(10, 6)) # Cria uma figura com tamanho 10 polegadas por 6 polegadas
plt.plot(rpm, eficiencia, label='Eficiência Térmica', color='blue')
plt.title('Eficiência Térmica do Motor em Função das RPM')
plt.xlabel('RPM')
plt.ylabel('Eficiência Térmica (%)')
plt.legend()
plt.grid(True)
plt.show()
Gráficos de Barras
Os gráficos de barras são usados para comparar valores entre diferentes grupos. São particularmente úteis quando você deseja visualizar
diferenças de tamanho entre os grupos.
plt.figure(figsize=(10, 6))
plt.bar(ligas, resistencia, color=['black', 'red', 'green', 'blue'])
plt.title('Resistência à Tração de Diferentes Ligas Metálicas')
plt.xlabel('Liga Metálica')
plt.ylabel('Resistência à Tração (MPa)')
plt.show()
Adicionando Títulos
Para adicionar um título a um gráfico em Matplotlib, você pode usar o método plt.title() .
Adicionando Subtítulos
Matplotlib não possui um método integrado específico para subtítulos. No entanto, subtítulos podem ser adicionados usando o método
plt.suptitle() para o subplot geral ou plt.text() para posições específicas.
plt.figure()
plt.suptitle("Título Principal: Análise de Dados", fontsize=16)
plt.title("Subtítulo: Resultados Preliminares")
plt.plot([0, 1, 2, 3], [0, 1, 4, 9])
plt.show()
Os métodos plt.xlabel() e plt.ylabel() são usados para adicionar rótulos aos eixos X e Y, respectivamente.
plt.figure(figsize=(10, 6))
plt.hist(resistencia_tracao, bins=10, color='skyblue', edgecolor='black')
plt.title('Distribuição da Resistência à Tração')
plt.xlabel('Resistência à Tração (MPa)')
plt.ylabel('Frequência')
plt.grid(axis='y')
plt.show()
# Dados de exemplo
data = {
'Temperatura': [20, 25, 30, 35, 40, 45, 50, 55, 60, 65],
'Eficiencia': [82, 84, 85, 86, 85, 84, 83, 82, 80, 78],
'Pressao': [1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5]
}
df = pd.DataFrame(data)
# Dados de exemplo
altura_homem = np.random.normal(175, 10, 100)
peso_homem = altura_homem * 0.7 + np.random.normal(0, 5, 100)
# Exibindo o gráfico
plt.tight_layout()
plt.show()
Subplots
Subplots são úteis para comparar diferentes conjuntos de dados ou visualizações. Matplotlib permite criar subplots facilmente com
plt.subplot() .
Criando Subplots
Você pode criar uma figura com múltiplos subplots especificando o número de linhas e colunas.
# Primeiro subplot
plt.subplot(1, 2, 1) # (linhas, colunas, índice do subplot)
plt.plot([0, 1, 2, 3], [0, 1, 4, 9])
plt.title("Primeiro Subplot")
# Segundo subplot
plt.subplot(1, 2, 2)
plt.plot([0, 1, 2, 3], [0, -1, -4, -9])
plt.title("Segundo Subplot")
x = range(1, 10)
y = [2 * xi for xi in x]
# Alterando a cor para vermelho (r) e o estilo da linha para tracejado (--).
plt.plot(x, y, color='red', linestyle='--')
plt.title('Gráfico Personalizado: Cor e Estilo de Linha')
plt.show()
Marcadores
Para destacar cada ponto de dados em um gráfico de linhas, você pode utilizar marcadores. Isso é especialmente útil em gráficos de
dispersão ou para enfatizar pontos de dados específicos.
Legendas
Legendas são cruciais para gráficos que contêm múltiplas linhas ou categorias, pois ajudam a diferenciar entre as várias séries de dados.
Grid (Grade)
A adição de uma grade ao gráfico melhora a legibilidade, permitindo que os leitores estimem valores individuais com mais precisão.
plt.plot(x, y)
plt.grid(color='grey', linestyle='-', linewidth=0.25, alpha=0.5)
plt.show()
Personalização Avançada
Spines
# Plotando os dados
ax.plot(x, y)
# Mostrando o gráfico
plt.show()
Ocultar Spines:
Você pode ocultar spines definindo sua cor para 'none'.
# Ocultar spines
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
Deslocamento dos Spines:
Você pode deslocar os spines do centro do gráfico para qualquer posição desejada.
Spines Duplos:
Anotações
Anotações permitem destacar pontos de dados específicos ou áreas de um gráfico, adicionando uma camada extra de informação. A
sintaxe básica para annotate() é:
arrowstyle: Controla o estilo da seta. Além do estilo padrão, há várias outras opções disponíveis, como '->' , '-|>' , 'fancy' , etc.
bbox: Permite adicionar uma caixa ao redor do texto da anotação, que pode ser personalizada com cor de fundo, borda e
transparência.
Posição de legendas
# Personalização da legenda
plt.legend(loc='upper right', fontsize=10, shadow=True)
Para criar animações, usamos a função FuncAnimation do módulo matplotlib.animation . Ela é especialmente útil quando queremos
animar um gráfico ou uma figura com base em uma sequência de dados ou frames.
1. Parâmetros Principais:
fig : A figura a ser animada.
func : A função que será chamada a cada frame para atualizar o conteúdo da figura.
frames : A sequência de dados (ou número de frames) a serem usados na animação. Se for um inteiro, exemplo x = 10 , a função
a interpreta como range(10) ; se for uma lista ou um outro iterável, usa o conteúdo armazenado. Esses valores são passados
como argumento para a função func .
init_func : Uma função que será chamada uma única vez para inicializar a animação.
blit : Um valor booleano que indica se deve-se usar a técnica de "blitting" para otimizar a animação. Isso basicamente atualiza
somente a parte que mudou do gráfico, melhorando a performance de renderização.
2. Argumentos Opcionais:
fargs : Argumentos adicionais para a função func .
interval : O intervalo de tempo entre os frames em milissegundos.
repeat : Se a animação deve repetir após completar todos os frames.
repeat_delay : O tempo de espera em milissegundos antes de reiniciar a animação.
save_count : O número de frames a serem incluídos em uma animação salva (sempre que save for chamado).
3. Retorno:
Um objeto FuncAnimation que representa a animação. Ele pode ser mostrado na tela ou salvo em um arquivo de vídeo.
4. Funcionalidade:
A função func é chamada para cada frame da animação, e ela é responsável por atualizar o conteúdo da figura com base nos
dados correspondentes a esse frame.
A função init_func é chamada uma vez no início da animação e é usada para inicializar o estado da figura.
Se blit for definido como True , a animação pode ser otimizada usando a técnica de "blitting", que atualiza apenas as partes da
figura que mudaram entre os frames.
fig, ax = plt.subplots()
# Em frames, passamos quantas figuras a animação terá. Esse argumento é interpretado como range(10), ou seja, a FuncAnimation
gera um iterável que vai de 0 a 9 e que é usado para chamar cada item em "temperaturas" pelo índice.
ani = animation.FuncAnimation(fig, animate, frames=10, interval=1000)
plt.show()
O resultado é uma animação com o gráfico de temperatura a cada ano.
# Função de animação
def animate(frame):
# A cada frame, somamos um valor à X. Esse valor vem do
# iterável range(100) passado em 'frames' na função FuncAnimation
line.set_ydata(np.sin(x + frame / 10))
return line,
# Configurações do gráfico
ax.set_xlim(0, 2 * np.pi)
ax.set_ylim(-1, 1)
# Criação da animação
# DICA: para deixar a animação mais usave, passe frames=np.arange(0, 100, 0.1) e interval 5
ani = FuncAnimation(fig, animate, frames=100, interval=50)
# Exibição da animação
plt.show()
Exemplo 3: Animação de Caminho Circular
# Parâmetros
theta = np.linspace(0, 2 * np.pi, 100)
def init():
ax.set_xlim(-1.5, 1.5)
ax.set_ylim(-1.5, 1.5)
return point,
# Função de animação
def animate(frame):
# a cada frame, calculamos as coordenadas x e y do ponto.
x, y = circle_coordinates(frame)
point.set_data(x, y)
return point,
# Criação da animação
# Aqui, frames recebe a lista theta. Como uma lista é iterável, cada
# item dessa lista se torna um frame da animação e é passado para a função "animate"
ani = FuncAnimation(fig, animate, frames=theta, init_func=init, blit=True)
# Exibição da animação
plt.tight_layout()
plt.show()
Introdução
Plotly fornece duas interfaces de usuário principais: Plotly Express e Graph Objects. Plotly Express é a interface de alto nível que facilita a
criação de gráficos com código mínimo, ideal para exploração de dados rápida e visualizações simples. Graph Objects, por outro lado,
oferece controle mais detalhado sobre a aparência do gráfico, permitindo personalizações avançadas.
Antes de começar, você precisa instalar o Plotly. Isso pode ser feito facilmente com pip:
gapminder: Dados demográficos e econômicos de vários países ao longo do tempo, útil para visualizações temporais e geográficas.
tips: Dados de gorjetas coletados de um restaurante, incluindo o total da conta, a gorjeta, o sexo do pagador, se era dia de semana ou
fim de semana, e mais.
iris: Clássico conjunto de dados que contém as medidas de várias partes de flores de íris de três espécies diferentes.
election: Dados de uma eleição fictícia em um distrito, útil para visualizações de mapa.
wind: Dados de velocidade e direção do vento, que podem ser usados para gráficos de vetor ou rosa dos ventos.
import plotly.express as px
# Base de dados de exemplos: https://plotly.com/python-api-reference/generated/plotly.data.html
px.data.__all__
Este exemplo cria um gráfico de linha mostrando a população do Canadá ao longo do tempo, utilizando dados de exemplo disponíveis
diretamente no Plotly Express.
import plotly.express as px
# Dados fictícios
df = px.data.gapminder().query("country=='Canada'")
fig = px.line(df, x='year', y='pop', title='População do Canadá ao longo do tempo')
fig.show()
Gráfico de Barras
Este gráfico de barras mostra as vendas totais por dia, com as barras coloridas por gênero, usando um conjunto de dados de gorjetas de
restaurante.
import plotly.express as px
fig.show()
Gráfico de Dispersão
Este gráfico de dispersão explora a relação entre a largura e o comprimento da sépala das flores de íris, colorindo os pontos de acordo com
a espécie.
import plotly.express as px
fig.show()
import plotly.graph_objects as go
import numpy as np
fig.show()
Este exemplo cria um gráfico de superfície 3D do Plotly, mostrando uma função matemática. A interatividade permite ao usuário rotacionar,
ampliar e explorar a superfície para entender melhor a relação entre as variáveis.
Gráficos de dispersão 3D são úteis para explorar relações entre três variáveis numéricas. Eles podem fornecer insights valiosos sobre a
estrutura e correlações dos dados.
import plotly.graph_objects as go
import numpy as np
Exemplo de Linhas 3D
Este gráfico traça uma linha 3D seguindo os valores especificados em x , y , e z , ilustrando uma trajetória ou evolução ao longo do tempo
em três dimensões.
fig.update_layout(
title='Gráfico de Linhas 3D',
scene=dict(xaxis_title='Eixo X',
yaxis_title='Eixo Y',
zaxis_title='Eixo Z'),
margin=dict(l=65, r=50, b=65, t=90), # Margem, em pixels
width=1200, height=600)
fig.show()
Mapas com Plotly
Plotly também facilita a criação de mapas interativos, que são essenciais para visualizar dados geográficos, desde a distribuição de
população até padrões meteorológicos.
import plotly.express as px
fig.show()
Mapa de Calor Geográfico com Plotly
Mapas de calor geográficos são eficazes para visualizar dados em relação a localizações geográficas, com cores representando a
intensidade ou magnitude de uma variável.
Este exemplo cria um mapa de calor geográfico que mostra o Produto Interno Bruto (PIB) per capita de diferentes países em 2007. A
intensidade da cor em cada país representa a magnitude do seu PIB per capita, permitindo uma análise rápida e visual das disparidades
econômicas globais.
import plotly.express as px
1. Álgebra Linear: Oferece solvers eficientes para sistemas lineares, operações de matriz, decomposições e muito mais.
2. Otimização: Fornece algoritmos para minimização (ou maximização) de funções objetivas, com ou sem restrições.
3. Processamento de Sinais e Imagens: Inclui funcionalidades para filtragem, transformadas de Fourier, processamento de imagens e
muito mais.
4. Integração Numérica: Oferece métodos para integração numérica de funções.
5. Interpolação: Fornece ferramentas para interpolação de dados em uma ou mais dimensões.
6. Estatísticas: Inclui funções para estatísticas descritivas, testes de hipóteses, distribuições de probabilidade e muito mais.
7. Processamento de Sinais: Oferece uma ampla gama de ferramentas para análise e processamento de sinais.
8. Álgebra Simbólica: Integra-se com a biblioteca SymPy para manipulação de expressões matemáticas simbolicamente.
Funcionalidades Principais
1. Integração Numérica
O SciPy fornece uma variedade de métodos para integração numérica, incluindo quadratura numérica adaptativa, quadratura Gaussiana e
muito mais. Esses métodos são úteis para calcular integrais definidas numericamente, especialmente quando não há solução analítica
disponível.
2. Otimização
Para problemas de otimização, o SciPy oferece uma série de algoritmos eficientes, incluindo algoritmos de otimização não linear,
otimização global, otimização de mínimos quadrados e muito mais. Esses algoritmos são essenciais para encontrar os mínimos (ou
máximos) de funções objetivas em várias áreas da ciência e engenharia.
3. Álgebra Linear
Com recursos abrangentes de álgebra linear, o SciPy é capaz de lidar com sistemas de equações lineares, calcular autovalores e
autovetores, realizar decomposições de matriz e muito mais. Essas funcionalidades são fundamentais em muitas aplicações, como análise
de redes, processamento de sinais e aprendizado de máquina.
O SciPy oferece uma ampla gama de ferramentas para processamento de sinais e imagens, incluindo filtragem, transformadas de Fourier,
convolução e muito mais. Essas funcionalidades são vitais em áreas como processamento de áudio, processamento de imagens médicas e
comunicações digitais.
Subpacotes
A bibliteca é subdividida em vários subpacotes. Eles são listados abaixo.
Subpacote Descrição
cluster Algoritmos de agrupamento
constants Constantes físicas e matemáticas
fftpack Rotinas de Transformada Rápida de Fourier
integrate Integração e solucionadores de equações diferenciais ordinárias
interpolate Interpolação e splines de suavização
io Entrada e Saída
linalg Álgebra Linear
ndimage Processamento de imagem N-dimensional
odr Regressão de distância ortogonal
optimize Rotinas de otimização e busca de raízes
signal Processamento de sinal
sparse Matrizes esparsas e rotinas associadas
spatial Estruturas e algoritmos de dados espaciais
special Funções especiais
stats Distribuições e funções estatísticas
Constants
A biblioteca possui uma base de dados de constantes físicas e matemáticas que pode ser utilizada nos códigos. Existem constantes de
várias categorias, entre elas:
Conversão métrica
Binário
Massa
Ângulo
Tempo
Distância/comprimento
Pressão
Volume
Velocidade
Temperatura
Energia
Potência
Força
Em cada categoria os valores retornados são em relação às unidades de medida do SI, ou seja, em distância os valores retornados
são em metro; em pressão em pascais; em temperatura em kelvin; etc. Uma descrição detalhada com exemplos pode ser encontrada
nos links abaixo:
https://www.w3schools.com/python/scipy/scipy_constants.php
https://docs.scipy.org/doc/scipy/reference/constants.html#module-scipy.constants
Exemplo:
Algebra linear
Conceitos Fundamentais da Álgebra Linear
Matrizes e Vetores
Uma matriz é uma coleção retangular de números dispostos em linhas e colunas. Um vetor é uma matriz unidimensional com apenas uma
coluna (ou uma linha, caso seja um vetor linha). No SciPy, matrizes e vetores são representados usando o objeto numpy.ndarray ,
fornecendo uma ampla variedade de operações e funcionalidades.
Operações Básicas
O SciPy permite realizar uma série de operações básicas com matrizes e vetores, incluindo adição, subtração, multiplicação por escalar,
multiplicação de matrizes e muito mais. Essas operações são executadas de forma eficiente usando as funções fornecidas pelo SciPy.
Resolver sistemas de equações lineares é uma tarefa comum em muitas áreas da ciência e engenharia. O SciPy oferece várias funções
para resolver sistemas lineares, incluindo scipy.linalg.solve para sistemas lineares densos e scipy.sparse.linalg.spsolve para
sistemas esparsos.
Autovalores e Autovetores
Os autovalores e autovetores de uma matriz são propriedades importantes com uma ampla variedade de aplicações, incluindo análise de
estabilidade de sistemas dinâmicos, redução de dimensionalidade e muito mais. O SciPy fornece funções para calcular autovalores
( scipy.linalg.eigvals ) e autovetores ( scipy.linalg.eig ).
Exemplos Práticos
Exemplo 1: Resolução de um Sistema Linear
Vamos resolver o seguinte sistema de equações lineares usando o SciPy:
import numpy as np
from scipy.linalg import solve
# Definindo os coeficientes
A = np.array([[1, 2], [3, 5]])
b = np.array([3, 7])
# Resolvendo o sistema
# https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.solve.html#scipy.linalg.solve
x = solve(A, b)
print("Solução do sistema:", x)
Se for uma matriz singular (determinante igual a zero), ocorrerá um erro "LinAlgError".
# Definindo a matriz
A = np.array([[2, 1], [1, 3]])
print("Autovalores:", autovalores)
print("Autovetores:")
print(autovetores)
Exemplo 5: Decomposição LU
A decomposição LU é uma forma de decompor uma matriz em dois fatores, uma matriz triangular inferior (L) e uma matriz triangular
superior (U). Vamos realizar a decomposição LU para a seguinte matriz:
# Definindo a matriz
A = np.array([[2, 1, 1], [4, 3, 3], [8, 7, 9]])
# Realizando a decomposição LU
# https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.lu.html#scipy.linalg.lu
P, L, U = lu(A)
print("Matriz L:")
print(L)
print("Matriz U:")
print(U)
Interpolação
Introdução à Interpolação
A interpolação é útil quando temos um conjunto discreto de pontos de dados e desejamos estimar valores entre esses pontos. Por exemplo,
podemos usar interpolação para preencher lacunas em dados, suavizar curvas ou criar funções contínuas a partir de dados discretos.
Existem diferentes métodos de interpolação, como interpolação linear, interpolação polinomial, interpolação cúbica, entre outros. Cada
método tem suas próprias características e é adequado para diferentes tipos de dados e situações.
1. Interpolação Linear
A interpolação linear é o método mais simples, onde os valores intermediários são estimados a partir de uma linha reta entre pontos de
dados adjacentes.
import numpy as np
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt
# Dados de exemplo
x = np.array([0, 1, 2, 3, 4])
y = np.array([0, 2, 3, 1, 5])
# Dados de exemplo
x = np.linspace(0, 10, 11)
y = np.sin(x)
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d, CubicSpline
# Dados de exemplo
x = np.linspace(0, 10, 11)
y = np.sin(x)
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d, CubicSpline
# Dados de exemplo
x = np.linspace(0, 10, 11)
y = np.power(x, 2)
# Dados de exemplo
x = np.linspace(0, 10, 11)
y = np.sin(x)
Exemplos Práticos
Integrais Simples
A integração simples é o cálculo da integral de uma função em um único intervalo. O SciPy oferece o método quad para calcular integrais
simples numericamente.
Exemplo 1
1
2
∫ x dx
0
Exemplo 2
3
∫ xdx
−3
import scipy.integrate
func = lambda x: x
sol1=integrate.quad(func, -3, 3)
print(sol1)
# (0.0, 9.954756037365587e-14)
Exemplo 3
4
2
∫ x dx
0
Exemplo 4
∞
−x
∫ e dx
0
Exemplo 5
∫ axdx
0
f = lambda x, a: a*x
y, err = integrate.quad(f, 0, 1, args=(1,))
print(y)
# 0.5
y, err = integrate.quad(f, 0, 1, args=(3,))
print(y)
# 1.5
Integrais Duplas
A integração dupla é o cálculo da integral de uma função em uma região bidimensional. O SciPy oferece o método dblquad para calcular
integrais duplas numericamente.
Exemplo 1
2 1
2 2
∫ ∫ x + y dydx
0 0
import numpy as np
from scipy import integrate
f = lambda y, x: x*y**2
integrate.dblquad(f, 0, 2, 0, 1)
# (0.6666666666666667, 7.401486830834377e-15)
Exemplo 3
x=π/4 y=cos(x)
∫ ∫ 1dydx
x=0 y=sin(x)
f = lambda y, x: 1
integrate.dblquad(f, 0, np.pi/4, np.sin, np.cos)
# (0.41421356237309503, 1.1083280054755938e-14)
Exemplo 4
∫ ∫ axydydx
0 y=x
f = lambda y, x, a: a*x*y
integrate.dblquad(f, 0, 1, lambda x: x, lambda x: 2-x, args=(1,))
# (0.33333333333333337, 5.551115123125783e-15)
integrate.dblquad(f, 0, 1, lambda x: x, lambda x: 2-x, args=(3,))
# (0.9999999999999999, 1.6653345369377348e-14)
Integrais triplas
Da mesma forma, integrais triplas podem ser definidas pela função tplquad .
Exemplo 1
x=2 y=3 z=1
∫ ∫ ∫ xyzdzdydx
x=1 y=2 z=0
import numpy as np
from scipy import integrate
f = lambda z, y, x: x*y*z
integrate.tplquad(f, 1, 2, 2, 3, 0, 1)
# (1.8749999999999998, 3.3246447942574074e-14)
Exemplo 2
x=1 y=1−2x z=1−x−2y
∫ ∫ ∫ xyzdzdydx
x=0 y=0 z=0
f = lambda z, y, x: x*y*z
integrate.tplquad(f, 0, 1, 0, lambda x: 1-2*x, 0, lambda x, y: 1-x-2*y)
# (0.05416666666666668, 2.1774196738157757e-14)
Exemplo 3
Avalie a integral abaixo para os valores de a = [1, 3].
f = lambda z, y, x, a: a*x*y*z
integrate.tplquad(f, 0, 1, 0, 1, 0, 1, args=(1,))
# (0.125, 5.527033708952211e-15)
integrate.tplquad(f, 0, 1, 0, 1, 0, 1, args=(3,))
# (0.375, 1.6581101126856635e-14)
Exemplos Práticos
1. Mínimos Locais
# Minimizando a função
resultado = minimize(funcao, x0=0)
print("Mínimo local:", resultado.x)
# Mínimo local: [0.]
Aqui, "resultado" é um objeto que possui vários atributos, sendo um deles "x" como visto acima. Para ver todos, basta dar um print em
"resultado". Aqui, resultado.x retorna o valor de x para o qual a função é mínima, resultado.fun retorna a função avaliada para esse valor
de x, resultado.success e resultado.message mostram se iteração rodou com sucesso e a mensagem final. Outros parâmetros podem ser
compreendidos entrando nesse link
print(resultado)
# fun: 5.0
# hess_inv: array([[1]])
# jac: array([0.])
# message: 'Optimization terminated successfully.'
# nfev: 2
# nit: 0
# njev: 1
# status: 0
# success: True
# x: array([0.])
Exemplo 2: Minimização de uma Função Cosseno
A função Rosenbrock é uma função de teste comumente usada em otimização (ver https://en.wikipedia.org/wiki/Rosenbrock_function). Ela
tem o formato descrito a seguir, com mínimo global definido por (x, y) = (a, a²) onde f(x, y) = 0. Nesse exemplo, a = 1 e b = 100.
2. Mínimos Globais
Aqui, funcao deve ter o formato f(array), onde passamos um array 1-D de argumentos que serão desempacotados. A lista de tuplas
passada na função differential_evolution representa os limites para cada variável definida pela função.
Nesse exemplo, o mínimo global é -2 encontrado no ponto [-1.57079878, 3.14159218] = [-pi/2, pi]. Existem outros pontos em que isso
ocorre, mas aqui mostra-se somente um deles.
A função Schwefel é outra função de teste comum em otimização global. Ela é definida como na imagem abaixo onde d é a dimensão dela
dada por um número inteiro maior ou igual a 1. Ela tem mínimo global f(x) = 0 no ponto x = (420.968, ....., 420.968). Mais infos acesse esse
link.
# Minimizando a função Schwefel em um intervalo específico de -500 a 500 (intervalo usualmente definido)
d = 10
resultado = differential_evolution(schwefel, [(-500, 500)] * d)
print("Mínimo global:", resultado.x)
# Mínimo global: [420.96875345 420.96862494 420.96861954 420.96855124 420.96857548
# 420.96885351 420.96878977 420.96867113 420.96875851 420.96871339]
# fun: 0.0001272906038138899
# jac: array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
# message: 'Optimization terminated successfully.'
# nfev: 34716
# nit: 230
# success: True
# x: array([420.96875345, 420.96862494, 420.96861954, 420.96855124,
# 420.96857548, 420.96885351, 420.96878977, 420.96867113,
# 420.96875851, 420.96871339])
Portanto, independentemente do valor da dimensão d, a função terá mínimo em 0 para o mesmo conjunto de d pontos.
3. Otimização Restrita
Aqui, definimos as restrições com um dicionário. Em type, podemos usar "eq" para igualdade e "ineq" para desigualdade. Em "fun",
definimos a função. Se for igualdade, esta é considerada igual a zero; se for desigualdade, não-negativa (maior ou igual a zero).
É possível ver esse problema na imagem abaixo. Aqui, o plano verde representa a região compreendida pela restrição, e o ponto roxo é o
ponto de mínimo da função com a restrição aplicada.
Semelhante ao exemplo anterior, é possível ver esse problema na imagem abaixo. Aqui, o volume verde representa a região compreendida
pela inequação, e o ponto roxo é o ponto de mínimo da função com a restrição aplicada.
Processamento de sinal
O processamento de sinal é uma área fundamental em engenharia, ciência e tecnologia, que envolve a manipulação, análise e
interpretação de sinais para extrair informações úteis. O SciPy oferece uma variedade de funções e ferramentas para realizar uma ampla
gama de tarefas de processamento de sinal de forma eficiente (veja aqui).
Links úteis:
https://pieriantraining.com/scipy-signal-a-comprehensive-guide/
https://www.youtube.com/watch?v=TJGlxdW7Fb4&ab_channel=SteveBrunton
1. scipy.signal: Este subpacote fornece funções para análise e processamento de sinais, incluindo filtragem, convolução, espectro de
frequência, entre outros.
2. scipy.fft: Este subpacote oferece ferramentas para calcular a transformada rápida de Fourier (FFT) e suas variantes, que são
amplamente utilizadas na análise de sinais em domínio de frequência.
3. scipy.interpolate: Este subpacote oferece métodos para interpolação de sinais, permitindo a reconstrução de sinais suavizados ou
densificados (módulo abordado anteriormente).
import numpy as np
import scipy.fft as fft
import matplotlib.pyplot as plt
# Sinal composto
y = y1 + y2
# Normalização do sinal para se tornar um número inteiro de 16-bit, que abrange inteiros de -32768 a 32767.
# Ao dividir pelo valor máximo, o intervalo do sinal é escalado para entre -1 e 1, e o valor multiplicado o escala para o
intervalo acima.
y_norm = np.int16((y / y.max()) * 32767)
# Calcula as frequencias no centro de cada "caixa" calculada pela saida da fft, como se fosse um histograma.
# fs*duracao = número de pontos analizados
freqs = fft.fftfreq(fs*duracao, d=1/fs)
# ponto com valor de frequencia máxima (frequência de Nyquist, metade da taxa de amostragem):
print(f"Frequência máxima: {max(np.abs(Y))} Hz") # output: Frequência máxima: 22049.778433832136 Hz
Observe que existem 2 picos: em cerca de 10Hz e em 100Hz, justamente as frequências dos sinais que compuseram o sinal analisado.
Além disso, a amplitude em 100 Hz é cerca de um terço da amplitude em 10Hz, já que multiplicamos o sinal de alta frequência por 0.3 ( y2
= (y2*0.3) ).
odeint
A sintaxe da função odeint pode ser vista abaixo:
# Condições iniciais
y0 = [...] # Valores iniciais das variáveis dependentes
# Resolvendo as EDOs
sol = odeint(modelo, y0, t, args=(...))
solve_ivp
A função solve_ivp é mais versátil e pode ser usada para resolver sistemas de EDOs de ordem superior, além de permitir a especificação
de métodos de integração diferentes. Sua sintaxe básica é a seguinte:
# Condições iniciais
y0 = [...] # Valores iniciais das variáveis dependentes
# Resolvendo as EDOs
sol = solve_ivp(modelo, t_span, y0, t_eval=...)
Exemplos Práticos
Exemplo 1: Resolvendo uma EDO de Primeira Ordem
Vamos resolver a seguinte EDO de primeira ordem:
dx/dt = −0.5y
# Condição inicial
y0 = 1
# Resolvendo a EDO
y = odeint(modelo, y0, t)
# Plotando a solução
plt.figure(figsize=(8, 6))
plt.plot(t, y, label='y(t)')
plt.title('Solução da EDO de Primeira Ordem')
plt.xlabel('Tempo')
plt.ylabel('y')
plt.legend()
plt.grid(True)
plt.show()
Exemplo 2: Resolvendo uma EDO de Segunda Ordem
Vamos resolver a seguinte EDO de segunda ordem:
2 2 2
d y/dt + ω y = 0
# Condições iniciais
y0 = [0, 1]
# Resolvendo a EDO
sol = solve_ivp(modelo, t_span, y0)
# Plotando a solução
plt.figure(figsize=(8, 6))
plt.plot(sol.t, sol.y[0], label='y(t)')
plt.title('Solução da EDO de Segunda Ordem')
plt.xlabel('Tempo')
plt.ylabel('y')
plt.legend()
plt.grid(True)
plt.show()
Para mais informações sobre o uso dessas funções, recomendo a leitura do site:
https://danielmuellerkomorowska.com/2021/02/16/differential-equations-with-scipy-odeint-or-solve_ivp/comment-page-1/
Usando o SymPy
O SymPy é uma biblioteca Python que oferece recursos completos para matemática simbólica. Para começar a usar o SymPy, você precisa
importá-lo primeiro.
import sympy as sp
Símbolos e Variáveis
No SymPy, você pode criar símbolos e variáveis usando a função symbols . Por exemplo:
x, y = sp.symbols('x y')
Agora x e y são símbolos que podem ser usados em expressões matemáticas. Você também pode criar várias variáveis de uma vez,
como mostrado acima.
Expressões Matemáticas
Você pode criar expressões matemáticas usando símbolos e operadores matemáticos padrão. Por exemplo:
expr = x**2 + 2*x + 1
Simplificação de Expressões
O SymPy oferece funções para simplificar expressões matemáticas. Por exemplo:
simplified_expr = sp.simplify(expr)
Resolução de Equações
O SymPy pode resolver equações simbolicamente. Aqui, deve-se escrever a expressão igualando-a a zero. Por exemplo, para resolver a
equação x 2
, você pode fazer o seguinte:
− 4 = 0
solution = sp.solve(x**2 - 4, x)
# [-2, 2]
Isso retornará uma lista de soluções para a equação. Nesse caso, [-2, 2] .
Um outro exemplo é
Derivação e Integração
Você pode derivar e integrar expressões com o SymPy. Por exemplo, para calcular a derivada de x em relação a x, você pode fazer:
2
derivada = sp.diff(x**2, x)
integral = sp.integrate(x**2, x)
Retorna x 3
/3.
Exemplos Práticos
Aqui estão alguns exemplos práticos que demonstram o uso do SymPy:
x, y = sp.symbols('x y')
expr = (x**2 + 2*x + 1) / (x + 1)
simplified_expr = sp.simplify(expr)
print(simplified_expr) # x + 1
x = sp.symbols('x')
solution = sp.solve(x**2 - 4, x)
print(solution) # [-2, 2]
x = sp.symbols('x')
derivada = sp.diff(x**2, x)
integral = sp.integrate(x**2, x)
print("Derivada:", derivada)
print("Integral:", integral)
# Derivada: 2*x
# Integral: x**3/3
Exemplo 5: Limites
Podemos calcular limites de funções usando a função limit :
expr = (sp.sin(x)) / x
limite = sp.limit(expr, x, 0)
Exemplo 6: Matrizes
É possível trabalhar também com matrizes de maneira simbólica.
# Exemplo
# x + 4 y == 2
# -2 x + y == 14
system = Matrix(( (1, 4, 2), (-2, 1, 14)))
solve_linear_system(system, x, y)
Módulo 6
Introdução à POO - Classes, Objetos e Métodos
A Programação Orientada a Objetos (POO) é um paradigma de programação que ganhou popularidade significativa devido à sua
capacidade de modelar problemas de forma mais próxima à maneira como os humanos pensam e interagem com o mundo real. Neste
artigo, exploraremos os conceitos fundamentais da POO, incluindo classes, objetos e métodos, e também discutiremos brevemente as
diferenças entre a POO e a programação funcional.
O que é POO?
Em sua essência, a POO organiza o código em entidades chamadas objetos, que interagem uns com os outros através de mensagens.
Esses objetos são instâncias de classes, que são como plantas baixas para a criação desses objetos. Cada classe define um conjunto de
propriedades (também conhecidas como atributos) e comportamentos (métodos) que seus objetos terão.
Objetos e atributos
Uma classe é uma estrutura que define o comportamento e as propriedades de um tipo de objeto. Ela age como um modelo para criar
objetos. Por exemplo, se estivéssemos modelando um sistema de gerenciamento de biblioteca, poderíamos ter uma classe chamada
Livro , que teria atributos como título , autor , ano de publicação , entre outros. Uma vez que uma classe tenha sido definida, você
pode criar quantos objetos (instâncias) dessa classe forem necessários. Cada objeto terá seus próprios valores para os atributos definidos
pela classe.
class Livro:
def __init__(self, titulo, autor, ano_publicacao): # função de inicialização da classe Livro (ocorre todas as vezes que
uma classe for criada)
self.titulo = titulo # Atributo
self.autor = autor # Atributo
self.ano_publicacao = ano_publicacao # Atributo
Um atributo então é uma característica de um objeto. Um atributo pode ser acessado assim:
Neste exemplo, criamos uma classe Livro com três atributos: titulo , autor e ano_publicacao . Depois, criamos um objeto chamado
livro1 da classe Livro passando os valores correspondentes para o construtor __init__ . Para acessar os atributos desse objeto,
usamos a notação de ponto, seguida pelo nome do atributo ( livro1.titulo , livro1.autor , livro1.ano_publicacao ). Essa notação permite
que você recupere e modifique os valores dos atributos de um objeto. Para modificar um atributo, basta atribuir um novo valor:
Métodos
Os métodos são funções definidas dentro de uma classe que definem o comportamento dos objetos dessa classe. Eles permitem que os
objetos executem ações específicas e interajam com seus próprios dados. São basicamente funções que aquele objeto criado pela classe
pode executar. Por exemplo, podemos adicionar um método à classe Livro para exibir informações sobre o livro:
class Livro:
def __init__(self, titulo, autor, ano_publicacao):
self.titulo = titulo
self.autor = autor
self.ano_publicacao = ano_publicacao
Neste exemplo, adicionamos um método chamado exibir_informacoes à classe Livro . Este método imprime as informações do livro,
incluindo título, autor e ano de publicação. Observe que todos os métodos de uma classe devem aceitar self como primeiro parâmetro,
que é uma referência ao próprio objeto. Assim, essa variável representa uma referência à própria classe, e com ela podemos acessar os
métodos e atributos dessa classe.
1. __init__ : O Construtor
Vimos esse método na seção anterior e ele é crítico para a criação de uma classe em Python. Ele é usado para inicializar objetos de uma
classe. Este método é invocado automaticamente quando um novo objeto da classe é criado. É aqui que você define as propriedades
iniciais do objeto.
class Pessoa:
def __init__(self, nome, idade):
self.nome = nome
self.idade = idade
p1 = Pessoa("Alice", 30)
print(p1.nome) # Alice
print(p1.idade) # 30
class Pessoa:
def __init__(self, nome, idade):
self.nome = nome
self.idade = idade
def __str__(self):
return f"{self.nome}, {self.idade} anos"
p1 = Pessoa("Alice", 30)
print(p1) # Alice, 30 anos
print(str(p1)) # Alice, 30 anos
class MinhaLista:
def __init__(self, itens):
self.itens = itens
def __len__(self):
return len(self.itens)
class ListaPersonalizada:
def __init__(self, itens):
self.itens = itens
class Ponto:
def __init__(self, x, y):
self.x = x
self.y = y
p1 = Ponto(1, 2)
p2 = Ponto(3, 4)
adicao = p1 + p2
print(adicao.x, adicao.y) # 4 6
subtracao = p1 - p2
print(subtracao.x, subtracao.y) # -2 -2
Outros operadores similares são:
- .__sub__(self, other)
* .__mul__(self, other)
/ .__truediv__(self, other)
// .__floordiv__(self, other)
% .__mod__(self, other)
Esses são apenas alguns exemplos dos muitos métodos especiais disponíveis em Python. Ao entender e utilizar esses métodos, você pode
personalizar o comportamento das suas classes e objetos de forma poderosa e elegante, tornando seu código mais expressivo e fácil de
usar.
Lembre-se de consultar a documentação oficial do Python para obter uma lista completa dos métodos especiais e suas utilizações.
Experimente explorar e experimentar com eles para aproveitar ao máximo o poder da programação orientada a objetos em Python.
Herança em Python
https://blog.rocketseat.com.br/heranca-e-polimorfismo-em-python-um-guia-detalhado/
Herança é um mecanismo pelo qual uma classe pode herdar atributos e métodos de outra classe. A classe que herda é chamada de classe
filha ou subclasse, e a classe que é herdada é chamada de classe pai ou superclasse. A subclasse pode adicionar novos métodos ou
modificar os métodos herdados para adaptá-los às suas necessidades específicas.
Exemplo de Herança:
Aqui, criamos uma classe genérica para todos os animais que recebe dois argumentos: nome e som do animal. Depois, criamos duas
subclasses, uma específica para cachorros e outra para gatos. Estas classes herdam os atributos e os métodos da classe mãe "Animal", ou
seja, podemos reutilizar o código e a manutenção do código fica facilitada.
Perceba que elas possuem a linha super().__init__(nome, som, dono) . Essa linha chama ao construtor da classe mãe. Aqui as classes
filhas podem ter seus próprios métodos e atributos, como self.eh_vacinado_contra_raiva = eh_vacinado_contra_raiva em "Cachorro".
class Animal:
def __init__(self, nome, som):
self.nome = nome
self.som = som
def mostrar_detalhes(self):
print(f"Animal: {self.nome}, Som: {self.som}")
class Cachorro(Animal):
def __init__(self, nome, som, dono, raca, eh_vacinado_contra_raiva):
super().__init__(nome, som)
self.dono = dono
self.raca = raca
self.eh_vacinado_contra_raiva = eh_vacinado_contra_raiva
def mostrar_detalhes(self):
print(f"Animal: {self.nome}, Dono: {self.dono}, vacinou raiva: {self.eh_vacinado_contra_raiva}")
class Gato(Animal):
def __init__(self, nome, som, dono, raca):
super().__init__(nome, som)
self.dono = dono
self.raca = raca
Polimorfismo
https://www.pythonprogressivo.net/2018/11/Polimorfismo-O-que-Como-Usar-Como-fazer.html
Polimorfismo é o princípio que permite que objetos de diferentes classes sejam tratados de maneira uniforme, desde que tenham um
método em comum. Isso significa que um método pode agir de forma diferente dependendo do tipo do objeto que o invoca.
Vamos usar o exemplo anterior para explicar isso.
class Animal:
def __init__(self, nome, som):
self.nome = nome
self.som = som
def mostrar_detalhes(self):
print(f"Animal: {self.nome}, Som: {self.som}")
class Cachorro(Animal):
def __init__(self, nome, som, dono, raca, eh_vacinado_contra_raiva):
super().__init__(nome, som, dono)
self.raca = raca
self.eh_vacinado_contra_raiva = eh_vacinado_contra_raiva
def mostrar_detalhes(self):
print(f"Animal: {self.nome}, Dono: {self.dono}, vacinou raiva: {self.eh_vacinado_contra_raiva}")
class Gato(Animal):
def __init__(self, nome, som, dono, raca):
super().__init__(nome, som, dono)
self.raca = raca
Note que na classe Cachorro nós criamos um método "mostrardetalhes" tal como havíamos criado na superclasse Animal, porém alteramos
o que mostramos no output. Nas duas últimas linhas, chamamos esse método para cada um dos objetos criados a partir das classes
"Cachorro" e "Gato", respectivamente.
Note que em "Cachorro" o output foi de acordo com o que definimos na subclasse "Cachorro". Ou seja, seu objeto assumiu a forma
da _subclasse "Cachorro". Dizemos que o método da subclasse fez uma sobreposição, ele sobrepôs, passou por cima, do método da
superclasse. Assim, como os dados mudam de forma, chamamos isso de polimorfismo.
Encapsulamento
Encapsulamento é o princípio de limitar o acesso direto aos atributos e métodos de uma classe, permitindo que a implementação interna de
uma classe seja modificada sem afetar o código que a utiliza. Em Python, não há modificadores de acesso como em outras linguagens de
programação (por exemplo, private , protected , public ), mas podemos alcançar encapsulamento utilizando convenções de
nomenclatura e métodos especiais.
Exemplo de Encapsulamento:
class Pessoa:
def __init__(self, nome, idade):
self.__nome = nome # Atributo privado
self.__idade = idade # Atributo privado
self.tipo = 'Homo sapiens' # Atributo público
def get_nome(self):
return self.__nome
def get_idade(self):
return self.__idade
Neste exemplo, os atributos __nome e __idade são encapsulados dentro da classe Pessoa , o que significa que eles não podem ser
acessados diretamente de fora da classe. Eles são definidos usando dois símbolos de sublinha (ou underscore). Métodos de acesso, como
get_nome() e set_nome() , são fornecidos para permitir a leitura e a modificação desses atributos de forma controlada. Para testar, tente
acessar os atributos encapsulados por pessoa.__nome . Irá ser levantado o erro AttributeError com a mensagem: AttributeError:
'Pessoa' object has no attribute '__nome' , indicando que o atributo não existe (ele existe, mas está encapsulado).
Propriedades
As propriedades em Python são uma maneira de definir métodos de acesso (getter) e métodos de modificação (setter) para atributos de
uma classe, mas com uma sintaxe mais limpa e intuitiva. Isso nos permite manter o código mais legível e expressivo. Elas podem ser
acessadas pelo decorator @property .
class Pessoa:
def __init__(self, nome, idade):
self.__nome = nome # Atributo privado
self.__idade = idade # Atributo privado
@property
def nome(self):
return self.__nome
@nome.setter
def nomeSetter(self, novo_nome):
self.__nome = novo_nome
@property
def idade(self):
return self.__idade
@idade.setter
def idade(self, nova_idade):
if nova_idade >= 0:
self.__idade = nova_idade
else:
print("Idade inválida.")
Perceba que criamos duas propriedades: nome e idade , e cada um possui um setter : nomeSetter e idade . Aqui, nomeSetter poderia ter
sido nomeado como nome, porém coloquei explicitamente o que essa função faz para explicar o exemplo. Se esse for o caso, a
propriedade seria acessada por pessoa.nome ao invés de pessoa.nomeSetter.
Note que podemos acessar o nome da pessoa tanto por pessoa.nome quanto por pessoa.nomeSetter , porém só conseguimos alterar o
nome da pessoa usando pessoa.nomeSetter . Para ver isso, teste os comandos abaixo:
print(pessoa.nome) # Bob
print(pessoa.nomeSetter) # Bob
pessoa.nome = "Bob" # AttributeError: can't set attribute
Vamos dar outro exemplo. Vamos supor que temos uma classe Casa que contém um atributo de preço.
class Casa:
def __init__(self, preco):
self._preco = preco
Quando quisermos alterar o valor desse atributo, queremos que esse valor seja validado antes (por exemplo, validar se o novo valor é um
float e se é maior que zero, já que menor que zero não faz sentido). Para isso, definimos uma propriedade preço e configuramos um
setter (que nada mais é que uma função) para fazer essa alteração.
class Casa:
def __init__(self, preco):
self.__preco = preco
@property
def preco(self): # getter que retorna o atributo "preço"
return self.__preco
@preco.setter
def preco(self, new_price): # Setter que faz a validação do novo valor
if novo_preco > 0 and isinstance(novo_preco, float):
self.__preco = novo_preco
else:
print("Insira um preço válido")
Caso a gente tente dizer que o preço é -100, chegamos em um erro indicando que o preço é inválido:
casa = Casa(2500)
print(casa.preco) # 2500
casa.preco = -100 # Insira um preço válido
Existe também o método deleter que faz a deleção da propriedade. Veja abaixo:
@preco.deleter
def preco(self):
del self.__preco # Excluímos o atributo de preço do objeto
Ao chamarmos o comando del casa.preco e depois tentarmos acessar via casa.preco, um erro aparecerá: python AttributeError: 'Casa'
object has no attribute '_preco'
class ValorNegativoError(Exception):
def __init__(self, valor):
super().__init__(f"O valor {valor} não pode ser negativo.")
self.valor = valor
try:
area = calcular_area_retangulo(5, -3)
print("Área do retângulo:", area)
except ValorNegativoError as e:
print("Erro:", e)
Nesse código, criamos uma classe chamada "ValorNegativoError" que herda a superclasse Exceptions que, em Python, é a principal classe
de exceções. Esse tratamento garante que o código seja interrompido logo no começo e evita que a área seja negativa. Aqui capturamos
esse erro em um bloco try except como uma boa prática de programação.
class DivisaoPorZeroError(Exception):
def __init__(self):
super().__init__("Divisão por zero não é permitida.")
try:
resultado = dividir(10, 0)
print("Resultado da divisão:", resultado)
except DivisaoPorZeroError as e:
print("Erro:", e)
Dataclasses em Python
As dataclasses são uma maneira de criar classes para armazenar dados de forma mais concisa e legível em Python. Elas automatizam a
criação de métodos especiais, como __init__ , __repr__ e __eq__ , que são comumente usados para manipular objetos de dados. Com as
dataclasses, você pode definir campos de dados explicitamente e deixar o Python gerar automaticamente os métodos especiais para você.
1. Redução de Boilerplate: Elimina a necessidade de escrever métodos especiais repetitivos, como __init__ , __repr__ , __eq__ , entre
outros.
2. Legibilidade Aprimorada: Cria classes mais concisas e legíveis, tornando o código mais fácil de entender e manter.
3. Facilidade de Uso: Simplifica a manipulação de dados estruturados, reduzindo a quantidade de código necessário para trabalhar com
eles.
Aqui está a sintaxe básica:
@dataclass
class NomeDaClasse:
atributo1: Tipo1
atributo2: Tipo2
#...
Observações:
1. Importação do Decorador: Você precisa importar o decorador dataclass do módulo dataclasses antes de usá-lo. Isso é feito com a
instrução from dataclasses import dataclass .
2. Decorador @dataclass : O decorador @dataclass é usado antes da definição da classe para indicar que essa classe é uma
dataclasse. Ele automatiza a criação de métodos especiais, como __init__ , __repr__ , __eq__ , entre outros, com base nos atributos
definidos na classe.
3. Definição da Classe: Em seguida, você define a classe como faria normalmente em Python, mas sem a necessidade de definir
explicitamente métodos especiais como __init__ , __repr__ , etc.
4. Atributos: Dentro da classe, você define os atributos que deseja que a dataclasse tenha. Cada atributo é definido como uma variável,
seguida pelo seu tipo. Por exemplo, atributo1: Tipo1 .
Com dataclasses, Python automaticamente cria métodos especiais, como __init__ , __repr__ , __eq__ , __hash__ , entre outros, com base
nos atributos definidos. Para mais detalhes, veja a documentação: https://docs.python.org/3/library/dataclasses.html
@dataclass
class Ponto:
lugar: str
x: float = 0.0
y: float = 0.0
def mostra_pontos(self,):
print(f"O lugar {self.lugar} tem coordenadas ({self.x},{self.y})")
class Ponto:
def __init__(self, x, y):
self.x = x
self.y = y
@dataclass
class Pessoa:
nome: str
idade: int
altura: float
@dataclass
class Produto:
codigo: str
nome: str
preco: float
quantidade_estoque: int
# Criando um produto
produto1 = Produto("001", "Camiseta", 29.90, 100)
print("Informações do produto:", produto1)
Módulo 7
Introdução à SQL e aplicação em Python
O que é um Banco de Dados SQL?
Um Banco de Dados SQL é um sistema de gerenciamento de banco de dados relacional que utiliza a linguagem SQL para manipular e
consultar dados.
Ser relacional significa ser organizado por tabelas que armazenam dados organizados em linhas e colunas. Cada tabela é composta por
registros que representam instâncias individuais de dados e colunas que representam atributos desses registros. Em outras palavras,
organizar os dados em tabelas com colunas e linhas onde cada linha tem um identificador único. Esse tipo de BD pode ser exemplificado
com uma planilha feita em Excel que possui uma tabela de vendas do dia e outra tabela com dados de todos os clientes dessa loja.
Também existem as bases de dados não relacionais, que abrangem o que não é relacional, como armazenamento em arquivos JSON ou
grafos. Nesse curso, vamos ver sobre os relacionais.
Fundamentos do SQL
A SQL (Structured Query Language) é a linguagem padrão para interação com bancos de dados relacionais. Ela permite realizar diversas
operações, como consultas (queries), inserções, atualizações e exclusões de dados. Abaixo estão algumas das principais operações e
conceitos do SQL:
1. Consultas (Queries):
As consultas são comandos que permitem extrair informações específicas do banco de dados. Elas são realizadas principalmente através
do comando SELECT , que permite selecionar dados de uma ou mais tabelas baseados em critérios definidos.
2. Inserção de Dados:
O comando INSERT INTO é usado para adicionar novos registros a uma tabela existente.
3. Atualização de Dados:
Nessa query, estamos atualizando o email do usuário na tabela clientes com a condição do id ser igual a 1. Também podemos usar a
keyword where com o comando select .
4. Exclusão de Dados:
O comando DELETE FROM é usado para remover registros de uma tabela.
DELETE FROM clientes WHERE id = 1;
5. Junções (Joins):
As junções são utilizadas para combinar dados de duas ou mais tabelas com base em uma condição relacionada.
Nesse exemplo, estamos selecionando a tabela clientes e combinando-a com a tabela pedidos com o id como chave identificadora em
comum. Partindo da tabela combinada, selecionamos ( select ) as colunas nome da tabela clientes e numero da tabela pedidos . Existem
outros tipos de join, como left , right e outer joins. Cada um pode ser visualizado nna figura abaixo.
Resumidamente:
LEFT JOIN: todos os dados da tabela da esquerda, incluindo aqueles em comuns com a direita e aqueles exclusivos à tabela da
esquerda;
RIGHT JOIN: mesma coisa da LEFT, porem aplicado para a direita (ou seja, todos os dados da tabela da direita, incluindo aqueles em
comuns com a esquerda e aqueles exclusivos à tabela da direita).
SQLite e Python
SQLite é um sistema de gerenciamento de banco de dados relacional que não requer um servidor separado, o que o torna uma escolha
popular para aplicações que precisam de armazenamento local de dados. Ele é leve, rápido, eficiente e oferece suporte à maioria dos
recursos encontrados em sistemas de banco de dados mais robustos.
Você pode usar a função connect() do módulo sqlite3 para se conectar ao banco de dados SQLite. Se o banco de dados não existir, ele
será criado automaticamente.
import sqlite3
2. Criar um Cursor
Um cursor é usado para executar comandos SQL e interagir com o banco de dados. Você pode criar um cursor chamando o método
cursor() do objeto de conexão.
4. Manipular Dados
Você pode inserir, atualizar, excluir e consultar dados no banco de dados utilizando comandos SQL.
# Salvar as alterações
conn.commit()
# Fechar a conexão
conn.close()
import sqlite3
# Salvar as alterações
conn.commit()
# Fechar a conexão
conn.close()
Por exemplo, para recuperar todos os registros da tabela clientes , podemos executar o seguinte comando SQL:
import sqlite3
fetchone()
O método fetchone() retorna a próxima linha de resultado da consulta como uma tupla ou None se não houver mais linhas disponíveis.
Semelhante ao comando next() visto em generators .
fetchall()
O método fetchall() retorna todas as linhas de resultado da consulta como uma lista de tuplas, onde cada tupla é equivalente a uma
linha.
# Salvar as alterações
conn.commit()
Podemos passar uma lista de tuplas em conjunto com o comando cursor.executemany() para inserir vários registros em uma tabela de
uma vez:
novos_clientes = [
('Gabriel', 22, 'gabriel@email.com'),
('Antonio', 40, 'antonio@email.com'),
]
# Salvar as alterações
conn.commit()
Excluindo Dados
Para excluir dados de uma tabela, utilizamos o comando DELETE FROM . Vamos excluir o cliente "José" da tabela.
# Salvar as alterações
conn.commit()
import sqlite3
import sqlite3
INNER JOIN
O INNER JOIN retorna apenas os registros que possuem correspondência nas duas tabelas. Aqui, estamos unindo pelo id de cliente e
retornamos o nome e o numero do pedido.
LEFT JOIN
O LEFT JOIN retorna todos os registros da tabela da esquerda e os registros correspondentes da tabela da direita. Aqui, caso o registro em
clientes não tenha em pedidos, o número do pedido vem "None", indicando que o cliente não tem registro de pedidos.
# ('João', '12345')
# ('Maria', '67890')
# ('José', None)
# ('Ana', None)
# ('Gabriel', None)
# ('Antonio', None)
O comando "right join" é semelhante ao "left join", porém é o oposto: retorna todos os itens da tabela da direita e os registros
correspondentes da tabela da direita.
Já o "outer join" retorna todos os valores da tabela da esquerda e todos os valores da tabela da direita.
GROUP BY
O comando GROUP BY é usado para agrupar linhas que possuem o mesmo valor em uma ou mais colunas. Aqui a lógica é bastante
semelhante ao GROUPBY visto no módulo 3 sobre Pandas. Antes de dar esse exemplo, vamos adicionar uma nova coluna à tabela
"clientes".
import sqlite3
conn.commit()
conn.close()
Agora vamos descobrir quantos clientes existem por país (coluna "pais", sem acento).
# Exemplo de GROUP BY
cursor.execute("""
SELECT pais, COUNT(*)
FROM clientes
GROUP BY pais
""")
resultado = cursor.fetchall()
for linha in resultado:
print(linha)
# ('Brasil', 2)
# ('Espanha', 1)
# ('França', 2)
# ('Portugal', 1)
Aqui, usamos a função nativa do SQL count para contar o número de linhas da query retornada agrupada por país.
import pandas as pd
import sqlite3
# Fechar a conexão
conn.close()
# Fechar a conexão
conn.close()
Módulo 8
Introdução ao Web Scraping: Bibliotecas Requests, BeautifulSoup e Selenium
O Web Scraping é uma técnica utilizada para extrair informações de páginas da web de forma automatizada. Essa prática é comumente
empregada em diversas áreas, como pesquisa acadêmica, coleta de dados para análises, monitoramento de preços e muito mais. Neste
artigo, vamos explorar três das bibliotecas mais populares para realizar Web Scraping em Python: Requests, BeautifulSoup e Selenium.
1. Biblioteca Requests
A biblioteca Requests é amplamente utilizada para fazer requisições HTTP em Python de forma simples e eficiente. Com ela, é possível
recuperar o conteúdo de uma página da web. Vejamos um exemplo básico de como utilizá-la:
import requests
url = 'https://api.github.com'
response = requests.get(url)
if response.status_code == 200:
print(response.text)
else:
print('Erro ao acessar a página:', response.status_code)
O código acima faz uma requisição GET para a URL especificada e imprime o conteúdo HTML da página, caso a requisição seja bem-
sucedida.
2. Biblioteca BeautifulSoup
A biblioteca BeautifulSoup é utilizada para analisar e extrair informações de documentos HTML ou XML. Ela fornece métodos poderosos
para navegar na estrutura do documento e recuperar os dados desejados. Abaixo está um exemplo de como usar o BeautifulSoup para
extrair todos os links de uma página da web:
url = 'https://www.exemplo.com'
response = requests.get(url)
if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')
links = soup.find_all('a')
Este código primeiro analisa o conteúdo HTML da página usando BeautifulSoup e, em seguida, encontra todos os elementos <a> (links) na
página e imprime seus URLs.
3. Biblioteca Selenium
A biblioteca Selenium é uma ferramenta poderosa para automatizar a interação com navegadores da web. Ela é especialmente útil quando
o conteúdo de uma página da web é gerado dinamicamente por meio de JavaScript, já que o Selenium pode simular a interação humana,
como clicar em botões ou preencher formulários. Veja um exemplo de uso básico do Selenium:
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
time.sleep(1)
text_area = driver.find_element(by=By.NAME, value="my-textarea")
text_area.send_keys("Aqui coloco qualquer texto")
time.sleep(2)
driver.quit()
Este código abre uma instância do navegador (no exemplo, estamos usando o Chrome) e navega até a URL especificada. Em seguida,
encontra um botão na página usando XPath e clica nele. Também preenche um campo de entrada com um texto. Por fim, imprime o
conteúdo HTML da página e fecha o navegador.
Requisições HTTP
Uma requisição HTTP é uma mensagem enviada por um cliente (como um navegador da web) para um servidor web. Ela contém
informações sobre a ação desejada pelo cliente e pode incluir dados adicionais, como parâmetros de consulta ou conteúdo a ser enviado
ao servidor.
Métodos HTTP
Os métodos HTTP especificam a ação que o cliente deseja realizar no recurso identificado pelo URL. Aqui estão os métodos mais comuns:
1. GET: Solicita a representação de um recurso específico. Os parâmetros de consulta podem ser incluídos na URL.
2. POST: Envia dados ao servidor para processamento. Geralmente usado para enviar informações de formulário ou enviar dados para
serem processados.
3. PUT: Substitui todas as representações atuais do recurso de destino pelos dados enviados na requisição.
4. DELETE: Remove o recurso especificado.
1. GET
O método GET é utilizado para solicitar dados de um recurso específico. Não deve modificar o estado do servidor.
import requests
url = 'https://jsonplaceholder.typicode.com/posts'
response = requests.get(url)
if response.status_code == 200:
print(response.json()) # Imprime a lista de posts
else:
print('Erro ao fazer a requisição:', response.status_code)
2. POST
O método POST envia dados ao servidor, geralmente para criar um novo recurso.
import requests
url = 'https://jsonplaceholder.typicode.com/posts'
data = {
'title': 'foo',
'body': 'bar',
'userId': 1
}
response = requests.post(url, json=data)
if response.status_code == 201:
print(response.json()) # Imprime os dados do novo post criado
else:
print('Erro ao fazer a requisição:', response.status_code)
3. PUT
import requests
url = 'https://jsonplaceholder.typicode.com/posts/1'
data = {
'id': 1,
'title': 'foo',
'body': 'bar',
'userId': 1
}
response = requests.put(url, json=data)
if response.status_code == 200:
print(response.json()) # Imprime os dados atualizados do post
else:
print('Erro ao fazer a requisição:', response.status_code)
4. DELETE
O método DELETE remove um recurso específico do servidor.
import requests
url = 'https://jsonplaceholder.typicode.com/posts/1'
response = requests.delete(url)
if response.status_code == 200:
print('Recurso deletado com sucesso.')
else:
print('Erro ao fazer a requisição:', response.status_code)
import requests
response = requests.get("https://api.github.com")
Neste exemplo, você capturou o valor de retorno de get() , que é uma instância de Response , e armazenou-o em uma variável chamada
response . Agora, você pode usar response para ver muitas informações sobre os resultados da sua solicitação GET.
O primeiro dado que você pode obter de uma Response é o código de status, que informa o estado da solicitação.
Por exemplo:
print(response.status_code)
Isso mostra o valor da resposta. Isso é útil para verificar se uma requisição foi respondida com sucesso. Pode-se verificar se status_code
== 200, == 404, etc. Porém a biblioteca Requests permite usar o próprio objeto "response" para avaliar se a resposta foi bem sucedida.
Assim, podemos fazer:
if response:
print("Success!")
else:
raise Exception(f"Non-success status code: {response.status_code}")
Conteúdo
Para extrair o conteúdo em bytes, pode-se usar .content
response.content
# b'{"current_user_url":"https://api.github.com/user","current_user.....
Essa resposta é crua e normalmente não é tão facilmente trabalhada. Para isso, usa-se .text para converter para uma string e .encoding
para ajustar a codificação da string, como por exemplo utf-8.
response.encoding = "utf-8" # Opcional: a biblioteca Requests já infere isso. Porém podemos usar outro esquema de encoding
response.text
# '{"current_user_url":"https://api.github.com/user","current_user.....
Em geral a resposta pode ser serializada como um JSON, ou seja, é possível convertê-la para um dicionário e acessar seus elementos
pelas chaves desse dicionário.
response.json()
# {'current_user_url': 'https://api.github.com/user', ...}
type(response.json())
# <class 'dict'>
response.headers
# {'Server': 'GitHub.com',
# 'Date': 'Wed, 22 May 2024 02:35:57 GMT',
# 'Content-Type': 'application/json; charset=utf-8',
# ...
# 'Content-Length': '510',
# 'X-GitHub-Request-Id': 'D9CE:BD65E:D39CD27:D621D7B:664D5A14'
# }
Já as queries strings permitem passar parâmetros personalizados para as requisições get. Ou seja, podemos mandar uma requisição de
dados especificando o tipo de resposta, número de dados, filtros etc.
import requests
# Aqui filtramos a requisição buscando somente repositórios que usam a linguagem python, ordenando-os de forma decrescente e
se possuem estrela.
response = requests.get(
"https://api.github.com/search/repositories",
params={"q": "language:python", "sort": "stars", "order": "desc"}, # pode ser uma lista de tuplas também.
)
# Analise da resposta
json_response = response.json()
popular_repositories = json_response["items"]
for repo in popular_repositories[:3]:
print(f"Name: {repo['name']}")
print(f"Description: {repo['description']}")
print(f"Stars: {repo['stargazers_count']}\n")
# Name: Python
# Description: All Algorithms implemented in Python
# Stars: 180636
#
# Name: youtube-dl
# Description: Command-line program to download videos from YouTube.com and other video sites
# Stars: 128973
#
# Name: transformers
# Description: 🤗 Transformers: State-of-the-art Machine Learning for Pytorch, TensorFlow, and JAX.
# Stars: 126413
Vale destacar que cada site e API REST possui especificações próprias, portanto vale estudar pela documentação o que é possível fazer.
BeautifulSoup: Explorando e Extraindo Dados
BeautifulSoup é uma poderosa biblioteca Python usada para extrair dados de arquivos HTML e XML. Combinada com a biblioteca
requests , permite realizar web scraping de forma eficiente.
Instalação
Primeiro, instale as bibliotecas necessárias:
import requests
from bs4 import BeautifulSoup
url = 'https://realpython.github.io/fake-jobs/'
response = requests.get(url)
html_content = response.content
Para mostrar o conteúdo, use o comando print(html_content) . A estrutura HTML do site será mostrada.
# https://www.realpython.com
# https://realpython.github.io/fake-jobs/jobs/senior-python-developer-0.html
# https://www.realpython.com
# https://realpython.github.io/fake-jobs/jobs/energy-engineer-1.html
# https://www.realpython.com
# https://realpython.github.io/fake-jobs/jobs/legal-executive-2.html
# ...
Você pode filtrar vagas específicas usando palavras-chave. Aqui, passamos uma função lambda pelo parâmetro "string" para realizar a
filtragem dos dados por palavras chaves, por exemplo. Nesse caso, procuramos pelas tags 'h2' cujo texto contenham a palavra chave
"Python".
keyword = 'Python'
filtered_jobs = soup.find_all('h2', string=lambda text: keyword in text if text else False)
Instalação
Para instalar o Selenium, use o comando abaixo:
Configurando o Selenium
Primeiro, configure o Selenium e o driver do navegador, nesse caso o Chrome:
def get_driver():
# Configurar o driver do Chrome
options = webdriver.ChromeOptions()
# options.add_argument('--headless')
# options.add_argument('--disable-extensions')
Podemos passar alguns parâmetros para configurar o navegador. Nesse caso, deixei duas sugestões comentadas, a de ativação do modo
headless e a desativação de extensões do navegador. O primeiro ativa o navegador sem ativar a interface em si, ou seja, a automação roda
em background. Porém aqui a deixei desativada para o navegador aparecer. Outros parâmetros podem ser adicionados, bastar ver a
documentação da biblioteca aqui.
driver.get(rf"https://www.selenium.dev/selenium/web/web-form.html")
Esse site é fornecido pela organização responsável pelo Selenium para a realização de testes.
title = driver.title
# 'Web form'
url = driver.current_url
# 'https://www.selenium.dev/selenium/web/web-form.html'
Podemos também preencher campos de texto. Para isso, precisamos localizar o elemento e depois usar o comando send_keys.
Aqui, localizamos o campo Text input e adicionamos a string "Selenium". Esse campo tem o nome "my-text" (use a ferramenta inspecionar
elementos do navegador para descobrir o nome do elemento no HTML da página), e foi por esse nome que o localizamos. Podemos
localizar também por classe ou ID.
Seguindo essa lógica, o campo senha é chamado aqui de "my-password" e o campo Textarea de "my-textarea". Podemos preenchê-los
seguindo a mesma lógica.
p
Para limpar esses campos, use o método .clear() (Ex: text_box.clear() ).
c1 = driver.find_element(by=By.ID, value="my-check-1")
c1.click()
c1.is_selected()
O comando is_selected() retorna True ou False caso a caixa esteja marcada ou não, respectivamente. Botões também podem ser clicáveis.
# Clica o botão submit, que tem como classe CSS o valor "button"
submit_button = driver.find_element(by=By.CSS_SELECTOR, value="button")
submit_button.click()
Datas
Para definir o valor de uma data em um campo de calendário, podemos usar o comando send_keys().
Espera Implícita é simples de configurar e se aplica globalmente, mas pode levar a tempos de espera desnecessariamente longos
para elementos que carregam rapidamente.
Espera Explícita é mais precisa, permitindo definir condições específicas para diferentes elementos, mas requer mais configuração e
código adicional.
Espera Fluent oferece maior controle sobre a frequência das verificações e as exceções ignoradas, sendo ideal para cenários
complexos, mas também é mais complexa de configurar.
Espera implícita instrui o WebDriver a esperar um certo tempo antes de lançar uma exceção de "No Such Element Exception" se o
elemento não for encontrado imediatamente. É configurada uma vez e aplica-se a todas as buscas de elementos.
Espera explícita instrui o WebDriver a esperar por uma determinada condição antes de prosseguir. Isso pode ser configurado para esperar
por condições específicas, como a presença de um elemento ou a visibilidade de um elemento.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# Iniciando o ChromeDriver
driver = webdriver.Chrome()
# Fechando o navegador
driver.quit()
Espera Fluent é uma forma mais avançada de espera explícita que permite definir a frequência com que o WebDriver deve verificar a
condição antes de lançar uma exceção, além de permitir ignorar tipos específicos de exceções.
# Iniciando o ChromeDriver
driver = webdriver.Chrome()
# Fechando o navegador
driver.quit()
1. Entre no site acima. Abra o inspecionar elementos e vá na aba Network (ou Rede) e clique no botão indicado pela seta vermelha para
limpar o histórico de análise da rede, caso não esteja limpa.
2. Atualize a página. Vários itens começarão a aparecer. Clique no filtro de "Fetch/XHR" para mostrar itens do tipo JSON, que é o tipo de
resposta que estamos buscando. Esse tipo de resposta é facilmente "parseável" em um dicionário usando o comando, já visto,
response.json() .
3. Nesse ponto, é necessário verificar cada item da lista. Podemos analisar os Headers, o Payload, ter um Preview e a Resposta da
requisição. Abaixo, está selecionado o item que estamos buscando.
4. Após achar a requisição desejada, cliquei com botão direito e copie-a como cURL (bash).
5. Vá no site https://curlconverter.com/ para converter o texto copiado em um código já pronto para várias linguagens, inclusive Python.
Cole o conteúdo e copie o código gerado.
6. Pronto. O código já pode ser colado no projeto. Como a requisição nesse caso responde no formato JSON, o Python interpreta como
dicionário, facilitando a interação com os dados.
Em geral, virão várias informações que podem ser descartadas. Nesse caso, a variável dicionario "cookie" pode ser descartada pois
não é essencial.
Exemplo 2: Buscar resultados de venda de carros na WebMotors
Vamos buscar e extrair os resultados de pesquisa de veículos no site WebMotors e guardar os resultados.
2. Vamos, nesse exemplo, puxa pelo Toyota Corolla. Abrirá uma janela como essa. Aqui, vamos abrir a ferramenta de inspecionar
elementos.
3. Vá na aba Network (ou Rede) e clique no botão indicado pela seta vermelha para limpar o histórico de análise da rede, caso não
esteja limpa.
4. Atualize a página para mostrar a análise de rede e filtre por "Fetch/XHR".
7. Nesse exemplo, vamos usar a ferramenta Insomnia para pegar o código pronto. Basta colar a cURL no campo especificado e clicar em
Send para analisar a resposta. Observe que, em Preview, já conseguimos ver a resposta no formato JSON.
8. Para pegar o código pronto, basta clicar na seta ao lado do botão Send e clicar em Generate Client Code.
9. Pronto. O código já pode ser colado no editor. Como a requisição nesse caso responde no formato JSON, o Python interpreta como
dicionário, facilitando a interação com os dados.
Módulo 9
Introdução ao Streamlit para aplicações de dados.
Streamlit é uma biblioteca de código aberto em Python que permite a criação rápida e fácil de aplicações web interativas para visualização
e análise de dados. Ao contrário de outras bibliotecas de visualização, como Matplotlib ou Seaborn, que são usadas para criar gráficos e
visualizações estáticas, o Streamlit é projetado para criar interfaces de usuário dinâmicas e interativas.
Essa biblioteca é uma excelente escolha para criar dashboards interativos e aplicações web de forma rápida e sem precisar conhecer
conceitos de front-end. Algumas de suas vantagens então são:
Fácil de Usar: Com poucos comandos, você pode transformar um script Python em uma aplicação web interativa.
Integração com Python: Você pode usar todas as bibliotecas Python que já conhece e ama, como Pandas, NumPy, Matplotlib, etc.
Sem necessidade de conhecimento em front-end: Você não precisa saber HTML, CSS ou JavaScript para criar aplicações web
funcionais.
Atualização em Tempo Real: Qualquer alteração no código é refletida imediatamente na aplicação sem a necessidade de recarregar
a página.
Instalação do Streamlit
Para começar a usar o Streamlit, você precisa instalá-lo. Nesses exemplos, vamos usar a versão 1.29.0. A instalação pode ser feita
facilmente via pip.
import streamlit as st
if st.button('Clique Aqui'):
st.write('Botão clicado!')
2. Sliders
Sliders são usados para selecionar um valor dentro de um intervalo. Você pode criar sliders numéricos e de datas.
import streamlit as st
3. Caixas de Seleção
As caixas de seleção permitem selecionar ou desmarcar uma opção. Use a função st.checkbox() para criar caixas de seleção.
import streamlit as st
if st.checkbox('Mostrar mensagem'):
st.write('Caixa de seleção marcada!')
4. Seletores de Opções
Os seletores de opções permitem escolher um item de uma lista de opções. Use a função st.selectbox() para criar seletores de opções.
import streamlit as st
opcao = st.selectbox('Escolha uma opção', ['Opção 1', 'Opção 2', 'Opção 3'])
st.write('Opção selecionada:', opcao)
import streamlit as st
Exemplo simples:
import streamlit as st
# Título da aplicação
st.title('Aplicação Streamlit Simples')
# Seleção de gênero
gender = st.selectbox('Selecione seu Estado:', ['Masculino', 'Feminino', 'Outro'])
# Rodapé
st.text('Obrigado por usar a aplicação!')
import streamlit as st
import pandas as pd
import matplotlib.pyplot as plt
st.subheader('Gráfico de Vendas')
st.line_chart(df, x='Data', y='Vendas')
st.subheader('Gráfico de Vendas')
st.line_chart(df, x='Data', y='Vendas')
Isso abrirá uma nova aba no navegador com a aplicação web interativa.
import pandas as pd
# Dados de exemplo para o arquivo CSV
data = {
"Data": ["2024-01-01", "2024-01-02", "2024-01-03", "2024-01-04", "2024-01-05"],
"Vendas": [150, 200, 300, 250, 400],
"Despesas": [100, 150, 200, 150, 300]
}
df = pd.DataFrame(data)
file_path = "vendas_exemplo.csv"
df.to_csv(file_path, index=False)
print(f"Arquivo CSV criado com sucesso: {file_path}")
import streamlit as st
with col2:
st.header("Coluna 2")
st.write("Conteúdo da segunda coluna")
with col3:
st.header("Coluna 3")
st.write("Conteúdo da terceira coluna")
Você pode personalizar a largura das colunas especificando a proporção das larguras.
with col2:
st.header("Coluna 2")
st.write("Conteúdo da segunda coluna")
with col3:
st.header("Coluna 3")
st.write("Conteúdo da terceira coluna")
2. Usando Grids em Streamlit
Embora o Streamlit não tenha suporte direto para grids, você pode criar layouts complexos combinando múltiplas colunas e usando
containers.
import streamlit as st
with col1:
subcol1, subcol2 = st.columns([2, 1])
with subcol1:
st.write("Subcoluna 1")
with subcol2:
st.write("Subcoluna 2")
with col2:
subcol3, subcol4 = st.columns(2)
with subcol3:
st.write("Subcoluna 3")
with subcol4:
st.write("Subcoluna 4")
3. Estilização CSS
Para adicionar estilos personalizados em sua aplicação Streamlit, você pode utilizar o componente st.markdown com a opção
unsafe_allow_html para inserir CSS diretamente no seu código.
import streamlit as st
import streamlit as st
import pandas as pd
import plotly.express as px
# Título da aplicação
st.title('Aplicação Interativa com Streamlit')
Exemplo:
import streamlit as st
import folium
from streamlit_folium import st_folium
# Título da aplicação
st.title('Aplicação Streamlit com Mapas Folium')
# Centro do mapa
latitude = st.number_input('Digite a latitude do centro do mapa:', value=0.0)
longitude = st.number_input('Digite a longitude do centro do mapa:', value=0.0)
# Criação do mapa
map = folium.Map(location=[latitude, longitude], zoom_start=2)
# Adicionando um marcador
folium.Marker([latitude, longitude], popup='Centro do Mapa').add_to(map)
# Exibição do mapa
st_folium(map, width=700, height=500)
# Adicionando um rodapé
st.text('Obrigado por usar a aplicação de mapas!')
import streamlit as st
import pandas as pd
import matplotlib.pyplot as plt
# Configurando a sidebar
st.sidebar.header('Opções de Filtragem')
Após carregar o arquivo CSV, aplicamos os filtros selecionados e exibimos os dados filtrados em um gráfico.
# Aplicando filtros
df_filtrado = df[(df['Data'] >= data_inicio) & (df['Data'] <= data_fim) & (df['Tipo'] == tipo_sensor)]
st.write('Dados Filtrados:')
st.write(df_filtrado)
import pandas as pd
import numpy as np
# Dados de exemplo para o arquivo TXT com mais de 100 linhas com variações nos valores
dates = pd.date_range(start="2024-01-01", periods=150, freq='D')
data_extended = {
"Data": dates.strftime('%Y-%m-%d').tolist(),
"Tipo": ["Temperatura"] * 50 + ["Pressão"] * 50 + ["Vibração"] * 50,
"Valor": list(22.5 + np.random.randn(50) * 0.5) +
list(1.2 + np.random.randn(50) * 0.1) +
list(0.02 + np.random.randn(50) * 0.01)
}
df_extended = pd.DataFrame(data_extended)
file_path_extended = "dados_sensores_extended.txt"
df_extended.to_csv(file_path_extended, index=False, sep=',')
print(f"Arquivo TXT criado com sucesso: {file_path_extended}")
Primeiramente, vamos criar um arquivo que irá armazenar as credenciais. Aqui, vamos chamá-lo de config.yaml .
cookie:
expiry_days: 30
key: some_signature_key
name: some_cookie_name
credentials:
usernames:
gabriel:
email: gabriel@gmail.com
failed_login_attempts: 0
logged_in: false
name: Gabriel
password: $2b$12$b.vNGittcoabQOV/Qplcn.K/pJe12QdGMDr8nL7U0bNI6xrVSNvMu
jojo:
email: joao@email.com
failed_login_attempts: 0
logged_in: false
name: Joao
password: $2b$12$cTOBZKf1yo5SHaYynOeb1u1i/Y7WqJ8LFqClRHjMCAxSwKuz3q0D6
pre-authorized:
emails:
- melsby@gmail.com
- gabriel@gmail.com
- gabp@gmail.com
Partindo para o código, vamos iniciar chamando a função acima e importando as credenciais. Aqui, usa-se a biblitoeca nativa yaml que
carrega os dados como dicionário, portanto podemos acessar o conteúdo via chaves.
import datetime
import yaml
import streamlit as st
import streamlit_authenticator as stauth
from yaml.loader import SafeLoader
from streamlit_authenticator.utilities.hasher import Hasher
# Função que salva futuras alterações, como quando quisermos alterar a senha
def save_changes_configfile(config):
with open('config.yml', 'w') as file:
yaml.dump(config, file, default_flow_style=False)
Janela de login
Usa-se o método login para chamar o widget de login que irá aparecer na tela.
# Chamamos o widget de login e o colocamos na janela 'main' (poderia ser 'sidebar' também)
name, authentication_status, username = authenticator.login(location='main')
# LOGIN
if st.session_state["authentication_status"]:
authenticator.logout() # botão de logout
print(f"[{datetime.datetime.now()}] Usuário logado: {username} AuthStatus: {authentication_status}")
st.write(f'Olá *{st.session_state["name"]}*')
# Agora podemos mostrar o conteúdo confidencial
st.title('Conteúdo privado')
elif st.session_state["authentication_status"] is False:
st.error('Username/password is incorrect')
elif st.session_state["authentication_status"] is None:
st.warning('Please enter your username and password')
Resetar senha
Para resetar a senha de um usuário, vamos incluir o trecho abaixo caso ele esteja autenticado:
# RESET PASSWORD
if st.session_state["authentication_status"]:
try:
if authenticator.reset_password(st.session_state["username"]):
print(f'[{datetime.datetime.now()}] Senha modificada com sucesso')
st.success(f'[{datetime.datetime.now()}] Senha modificada com sucesso')
save_changes_configfile(config)
except Exception as e:
st.error(e)
Essa janela só irá aparecer quando o usuário estiver logado ( st.session_state["authentication_status"] == True ).
# REGISTRAR USUARIO
try:
email_of_registered_user, username_of_registered_user, name_of_registered_user =
authenticator.register_user(pre_authorization=False)
if email_of_registered_user:
print(f'[{datetime.datetime.now()}] Usuário registrado com sucesso')
st.success(f'[{datetime.datetime.now()}] Usuário registrado com sucesso')
save_changes_configfile(config)
except Exception as e:
st.error(e)
Vale ressaltar que as senhas salvas sempre serão hasheadas automaticamente pela biblioteca, ou seja, é um sistema que adiciona uma
camada de segurança a mais no projeto. Assim, mesmo que alguém tenha acesso ao arquivo config.yaml, a pessoa dificilmente conseguirá
descobrir a senha.
No Windows:
.\env_teste\Scripts\activate.bat
No macOS/Linux:
source env/bin/activate
Instale o Streamlit, Pandas e Matplotlib no ambiente virtual, no caso desse projeto que estamos deployando:
Dica: Remova a linha referente a pywin32==306 do arquivo requirements.txt , se houver, para evitar problemas de compatibilidade.
Para sair de um ambiente virtual, basta dar o comando "deactivate" no cmd.
3. Implante a Aplicação:
Selecione o repositório e a branch onde sua aplicação está localizada. Diga qual é o arquivo que contém a dash e coloque uma
url personalizada, se quiser.
Clique em "Deploy".
Pronto! Sua aplicação deve iniciar e poderá ser acessada de qualquer computador. Se der tudo certo, o Streamlit já irá ler o arquivo
requirements.txt e instalar todas as dependências para você.
Módulo 10
Introdução à Geração Automática de Relatórios
A geração automática de relatórios é uma prática essencial em muitas indústrias e áreas de trabalho, permitindo que os dados sejam
apresentados de forma clara, consistente e eficiente. Utilizar bibliotecas e ferramentas para automatizar este processo pode economizar
tempo, reduzir erros e proporcionar relatórios personalizados e detalhados. Uma dessas ferramentas é a biblioteca python-pptx , que
facilita a criação de apresentações PowerPoint diretamente através de scripts em Python.
Instalação
2. Slides
Um slide é uma única página em uma apresentação PowerPoint. Você pode adicionar slides à apresentação usando o método add_slide()
da classe Presentation .
4. Formas (Shapes)
As formas são os elementos que compõem um slide, como títulos, caixas de texto, imagens, gráficos, tabelas, etc. Cada slide possui uma
coleção de formas acessível através da propriedade shapes .
Os espaços reservados são caixas predefinidas que podem conter diferentes tipos de conteúdo, como texto, imagens ou gráficos. Eles são
definidos pelo layout do slide.
Exemplo Prático
Vamos criar um exemplo prático onde geramos uma apresentação simples com alguns slides.
Primeiro, vamos criar uma nova apresentação e adicionar um título ao primeiro slide.
# Cria uma nova apresentação ou abre uma se existir (passando o caminho pra essa apresentação no objeto Presentation)
prs = Presentation()
# Salva a apresentação
prs.save('exemplo_apresentacao.pptx')
# Adiciona conteúdo
content = slide.placeholders[1]
content.text = "Benefícios da automação:\n- Economia de tempo\n- Redução de erros\n- Relatórios consistentes\n-
Personalização fácil"
# Salva a apresentação
prs.save('exemplo_apresentacao.pptx')
# Adiciona conteúdo
content = slide.placeholders[1]
content.text = "Neste exemplo, mostraremos como:\n- Inserir texto\n- Personalizar cor do texto\n- Alterar fonte e tamanho\n-
Aplicar layouts"
p = text_frame.add_paragraph()
p.text = "Texto em verde"
p.font.color.rgb = RGBColor(0, 255, 0)
p = text_frame.add_paragraph()
p.text = "Texto em azul"
p.font.color.rgb = RGBColor(0, 0, 255)
# Salva a apresentação
prs.save('personalizacao_texto.pptx')
title = slide.shapes.title
title.text = "Personalização de Fonte e Tamanho"
content = slide.placeholders[1]
text_frame = content.text_frame
p = text_frame.add_paragraph()
p.text = "Fonte Times New Roman, Tamanho 24"
p.font.name = 'Times New Roman'
p.font.size = Pt(24)
p = text_frame.add_paragraph()
p.text = "Fonte Calibri, Tamanho 18"
p.font.name = 'Calibri'
p.font.size = Pt(18)
# Salva a apresentação
prs.save('personalizacao_texto.pptx')
# Define o título
title = slide.shapes.title
title.text = "Exemplo de Slide com Imagem"
# Salva a apresentação
prs.save('exemplo_com_imagem.pptx')
https://python-pptx.readthedocs.io/en/latest/dev/analysis/cht-chart-overview.html
https://python-pptx.readthedocs.io/en/stable/user/charts.html
https://python-pptx.readthedocs.io/en/latest/api/enum/XlChartType.html
# Dados do gráfico
chart_data = CategoryChartData()
chart_data.categories = ['Categoria 1', 'Categoria 2', 'Categoria 3']
chart_data.add_series('Série 1', (10, 20, 30))
chart_data.add_series('Série 2', (15, 25, 35))
# Personaliza o gráfico
chart.has_legend = True
chart.legend.position = XL_LEGEND_POSITION.BOTTOM
chart.legend.include_in_layout = False
# Salva a apresentação
prs.save('grafico_barra_editavel.pptx')
# Personaliza o gráfico
chart.has_legend = True
chart.legend.position = XL_LEGEND_POSITION.BOTTOM
chart.legend.include_in_layout = False
# Salva a apresentação
prs.save('grafico_linha_editavel.pptx')
# Personaliza o gráfico
chart.has_legend = True
chart.legend.position = XL_LEGEND_POSITION.RIGHT
chart.legend.include_in_layout = False
# Salva a apresentação
prs.save('grafico_pizza_editavel.pptx')
# Salva a apresentação
prs.save('apresentacao_com_imagem.pptx')
# Salva a apresentação
prs.save('exemplo_tabela.pptx')
Estilizando a Tabela
Podemos aplicar estilos à tabela, como alterar a cor de fundo das células, o tamanho e a cor da fonte, e adicionar bordas.
# Salva a apresentação
prs.save('exemplo_tabela_estilizada.pptx')
Estilizando Slides
Além de estilizar tabelas, você pode estilizar todo o slide, incluindo o plano de fundo, títulos e caixas de texto.
# Salva a apresentação
prs.save('slide_estilizado.pptx')
Por exemplo, para o próximo exemplo criei um slide com algumas caixas de texto, e as duas que quero alterar receberam os nomes de
temp_media e temp_max. Aqui pode ser qualquer nome, mas é importante que um mesmo nome não se repita num mesmo slide.
No segundo slide fiz a mesma coisa com um gráfico editável. Seu shape recebeu o nome "dados_sensor_temperatura".
Com isso configurado, salvo essa apresentação com o nome 'apr_atualizar.pptx' e guardo seu caminho no computador.
O código desse exemplo irá iterar sobre cada slide e irá procurar os shapes de texto e o shape de gráfico para atualizar seus conteúdos.
A primeira "find_shape_by_name" itera por todos os shapes de um slide até procurar um que tenha o nome passado no argumento
"shape_name".
Já "atualizar_texto_caixa" serve para atualizar uma caixa de texto de um "slide" que tenha o nome "nome_caixa" e que receberá o
texto "novo_texto".
A função "replace_paragraph_text_retaining_initial_formatting" troca o texto de uma caixa de texto sem fazer com que ela perca a
formatação (fonte, cor, tamanho etc.). Isso é importante principalmente no nosso caso que só queremos trocar o conteúdo.
Por fim "atualizar_dados_grafico" funciona para atualizar os dados do gráfico. Aqui, ele procura pelo shape e, se achar, troca os dados
de acordo com o que for passado em "categorias" e "valores".
Introdução ao ReportLab
Instalação do ReportLab
Para começar a usar o ReportLab, você precisa instalá-lo. A instalação pode ser feita facilmente usando o pip:
pip install reportlab
# Salva o PDF
c.save()
c.setFont("Helvetica-Bold", 14)
c.setFillColor(colors.red)
c.drawString(100, 780, "Texto em negrito e vermelho com fonte Helvetica-Bold e tamanho 14.")
c.setFont("Times-Italic", 16)
c.setFillColor(colors.green)
c.drawString(100, 760, "Texto em itálico e verde com fonte Times-Italic e tamanho 16.")
# Salva o PDF
c.save()
Adicionando Imagens
# Adiciona um texto
c.drawString(100, 550, "Imagem adicionada ao PDF.")
# Salva o PDF
c.save()
# Dados da tabela
data = [
['Coluna 1', 'Coluna 2', 'Coluna 3'],
['Dado 1', 'Dado 2', 'Dado 3'],
['Dado 4', 'Dado 5', 'Dado 6']
]
# Estiliza a tabela
style = TableStyle([
('BACKGROUND', (0, 0), (-1, 0), colors.grey),
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('BOTTOMPADDING', (0, 0), (-1, 0), 12),
('BACKGROUND', (0, 1), (-1, -1), colors.beige),
('GRID', (0, 0), (-1, -1), 1, colors.black)
])
table.setStyle(style)
# Monta o PDF
elements = [table]
doc.build(elements)
c.setFont("Helvetica", 12)
c.drawString(100, 800, "Texto padrão com fonte Helvetica e tamanho 12.")
c.setFont("Helvetica-Bold", 14)
c.setFillColor(colors.red)
c.drawString(100, 780, "Texto em negrito e vermelho com fonte Helvetica-Bold e tamanho 14.")
c.setFont("Times-Italic", 16)
c.setFillColor(colors.green)
c.drawString(100, 760, "Texto em itálico e verde com fonte Times-Italic e tamanho 16.")
c.save()
# Função para criar um PDF com uma imagem
def criar_pdf_com_imagem():
c = canvas.Canvas("exemplo_imagem.pdf", pagesize=A4)
width, height = A4
data = [
['Coluna 1', 'Coluna 2', 'Coluna 3'],
['Dado 1', 'Dado 2', 'Dado 3'],
['Dado 4', 'Dado 5', 'Dado 6']
]
table = Table(data)
style = TableStyle([
('BACKGROUND', (0, 0), (-1, 0), colors.grey),
('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
('ALIGN', (0, 0), (-1, -1), 'CENTER'),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('BOTTOMPADDING', (0, 0), (-1, 0), 12),
('BACKGROUND', (0, 1), (-1, -1), colors.beige),
('GRID', (0, 0), (-1, -1), 1, colors.black)
])
table.setStyle(style)
elements = [table]
doc.build(elements)
if __name__ == "__main__":
main()