vitormartinotti

Untitled

Oct 22nd, 2025
708
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.77 KB | None | 0 0
  1. import tkinter as tk
  2. from tkinter import ttk, messagebox
  3. import matplotlib
  4. # Configura o backend do Matplotlib para funcionar com Tkinter
  5. matplotlib.use('TkAgg')
  6.  
  7. from matplotlib.figure import Figure
  8. from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
  9. import numpy as np
  10.  
  11. class AppPessoas(tk.Tk):
  12.     """Classe principal da aplicação Tkinter."""
  13.     def __init__(self):
  14.         super().__init__()
  15.         self.title("Cadastro e Gráfico de Pessoas")
  16.         self.geometry("800x600")
  17.  
  18.         # Lista para armazenar os dados de pessoas: [{"idade": 30, "peso": 75}, ...]
  19.         self.dados_pessoas = []
  20.  
  21.         # Configura as abas
  22.         self.notebook = ttk.Notebook(self)
  23.         self.notebook.pack(pady=10, padx=10, expand=True, fill="both")
  24.  
  25.         # Cria as abas
  26.         self.aba_cadastro = ttk.Frame(self.notebook)
  27.         self.aba_grafico = ttk.Frame(self.notebook)
  28.  
  29.         self.notebook.add(self.aba_cadastro, text="1. Cadastro")
  30.         self.notebook.add(self.aba_grafico, text="2. Gráfico")
  31.        
  32.         # Vincula a função de atualização ao evento de mudança de aba
  33.         self.notebook.bind("<<NotebookTabChanged>>", self.on_tab_change)
  34.  
  35.         # Configura o conteúdo de cada aba
  36.         self.setup_aba_cadastro()
  37.         self.setup_aba_grafico()
  38.  
  39.     def setup_aba_cadastro(self):
  40.         """Configura os widgets na aba de Cadastro."""
  41.        
  42.         # Frame principal para centralizar
  43.         frame_cadastro = ttk.Frame(self.aba_cadastro, padding="20")
  44.         frame_cadastro.pack(expand=True, anchor="center")
  45.  
  46.         # Rótulo e campo para Idade
  47.         ttk.Label(frame_cadastro, text="Idade (anos):").grid(row=0, column=0, pady=10, sticky="w")
  48.         self.entry_idade = ttk.Entry(frame_cadastro, width=15)
  49.         self.entry_idade.grid(row=0, column=1, pady=10, padx=5, sticky="ew")
  50.  
  51.         # Rótulo e campo para Peso
  52.         ttk.Label(frame_cadastro, text="Peso (kg):").grid(row=1, column=0, pady=10, sticky="w")
  53.         self.entry_peso = ttk.Entry(frame_cadastro, width=15)
  54.         self.entry_peso.grid(row=1, column=1, pady=10, padx=5, sticky="ew")
  55.  
  56.         # Botão para adicionar
  57.         botao_adicionar = ttk.Button(frame_cadastro, text="Adicionar Pessoa", command=self.adicionar_pessoa)
  58.         botao_adicionar.grid(row=2, column=0, columnspan=2, pady=20)
  59.        
  60.         # Rótulo para mostrar a contagem de pessoas
  61.         self.label_contagem = ttk.Label(frame_cadastro, text=f"Pessoas cadastradas: {len(self.dados_pessoas)}")
  62.         self.label_contagem.grid(row=3, column=0, columnspan=2, pady=10)
  63.  
  64.     def adicionar_pessoa(self):
  65.         """Coleta, valida e armazena os dados de idade e peso."""
  66.         try:
  67.             idade = int(self.entry_idade.get())
  68.             peso = float(self.entry_peso.get().replace(',', '.'))
  69.            
  70.             if idade <= 0 or peso <= 0:
  71.                  raise ValueError("Idade e Peso devem ser maiores que zero.")
  72.  
  73.             # Armazena os dados
  74.             self.dados_pessoas.append({"idade": idade, "peso": peso})
  75.            
  76.             # Limpa os campos de entrada
  77.             self.entry_idade.delete(0, tk.END)
  78.             self.entry_peso.delete(0, tk.END)
  79.            
  80.             # Atualiza a contagem
  81.             self.label_contagem.config(text=f"Pessoas cadastradas: {len(self.dados_pessoas)}")
  82.            
  83.             messagebox.showinfo("Sucesso", f"Pessoa adicionada: Idade {idade}, Peso {peso}kg.")
  84.            
  85.         except ValueError as e:
  86.             messagebox.showerror("Erro de Entrada", f"Por favor, insira valores válidos: {e}")
  87.         except Exception as e:
  88.             messagebox.showerror("Erro", f"Ocorreu um erro: {e}")
  89.  
  90.     def setup_aba_grafico(self):
  91.         """Configura a área de desenho do gráfico na aba de Gráfico."""
  92.        
  93.         # Cria a Figura (área de desenho) do Matplotlib
  94.         self.figura = Figure(figsize=(5, 5), dpi=100)
  95.         self.eixo = self.figura.add_subplot(111)
  96.  
  97.         # Cria o Canvas do Tkinter a partir da Figura
  98.         self.canvas = FigureCanvasTkAgg(self.figura, master=self.aba_grafico)
  99.        
  100.         # Adiciona o widget do canvas à aba
  101.         self.canvas_widget = self.canvas.get_tk_widget()
  102.         self.canvas_widget.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
  103.  
  104.         # Desenha o gráfico inicial vazio
  105.         self.plotar_grafico()
  106.  
  107.     def plotar_grafico(self):
  108.         """Gera o gráfico de Dispersão (Scatter Plot) com frequência de peso por idade."""
  109.        
  110.         # Limpa o gráfico anterior
  111.         self.eixo.clear()
  112.  
  113.         if not self.dados_pessoas:
  114.             self.eixo.text(0.5, 0.5, 'Nenhum dado cadastrado para exibir.',
  115.                            ha='center', va='center', transform=self.eixo.transAxes)
  116.             self.figura.canvas.draw()
  117.             return
  118.  
  119.         # 1. Preparar os dados para contagem de frequência
  120.         # Cria tuplas (idade, peso) e conta a frequência de cada combinação
  121.         combinacoes = [(d['idade'], d['peso']) for d in self.dados_pessoas]
  122.         from collections import Counter
  123.         frequencias = Counter(combinacoes)
  124.  
  125.         # 2. Separar os dados contados
  126.         idades = [c[0] for c in frequencias.keys()]
  127.         pesos = [c[1] for c in frequencias.keys()]
  128.         contagens = np.array(list(frequencias.values()))
  129.  
  130.         # 3. Mapear a contagem para o tamanho do ponto (escala visual)
  131.         # O tamanho (s) dos pontos no scatter plot será proporcional à frequência
  132.         # Usamos log para suavizar grandes diferenças e adicionamos um offset
  133.         tamanhos = (np.log(contagens + 1) * 200) + 50
  134.        
  135.         # 4. Desenhar o gráfico de dispersão (Scatter Plot)
  136.         scatter = self.eixo.scatter(idades, pesos, s=tamanhos, alpha=0.6, edgecolors='w', linewidth=1)
  137.  
  138.         # 5. Configurar rótulos e título
  139.         self.eixo.set_title("Frequência de Peso por Idade (Tamanho do Ponto = Frequência)")
  140.         self.eixo.set_xlabel("Idade (anos)")
  141.         self.eixo.set_ylabel("Peso (kg)")
  142.         self.eixo.grid(True, linestyle='--', alpha=0.7)
  143.         self.eixo.margins(0.1)
  144.        
  145.         # Garante que os valores dos eixos sejam inteiros se forem todos inteiros
  146.         if all(isinstance(i, int) for i in idades) and idades:
  147.             self.eixo.xaxis.set_major_locator(matplotlib.ticker.MaxNLocator(integer=True))
  148.  
  149.         # 6. Forçar o redesenho do canvas
  150.         self.figura.canvas.draw()
  151.  
  152.     def on_tab_change(self, event):
  153.         """Chamado quando o usuário muda de aba. Atualiza o gráfico se for para a aba de Gráfico."""
  154.         aba_selecionada = self.notebook.tab(self.notebook.select(), "text")
  155.        
  156.         if aba_selecionada == "2. Gráfico":
  157.             self.plotar_grafico()
  158.  
  159. # Ponto de entrada do programa
  160. if __name__ == "__main__":
  161.     app = AppPessoas()
  162.     app.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment