Last active
July 19, 2025 23:33
-
-
Save senapk/e18a2de83e7a5bbbf28b9f9822fb4cdb to your computer and use it in GitHub Desktop.
Gerador de porcentagens em cores no quadrado
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import matplotlib.pyplot as plt | |
| from matplotlib.figure import Figure | |
| from matplotlib.colors import ListedColormap | |
| import numpy as np | |
| from PIL import Image | |
| import random | |
| class Cat: | |
| def __init__(self, qtd: int, value: int): | |
| self.qtd = qtd | |
| self.value = value | |
| self.corner: tuple[int, int] = (0, 0) # Ponto de destino para alocação | |
| self.sorted_points: list[Point] = [] # Lista de pontos ordenados para alocação | |
| class Point: | |
| def __init__(self, x: int, y: int): | |
| self.x = x | |
| self.y = y | |
| self.free = True # Indica se o ponto está livre para alocação | |
| def __repr__(self): | |
| return f"Point({self.x}, {self.y})" | |
| def get_distance(p1: tuple[int, int], p2: tuple[int, int]) -> float: | |
| """Calcula a distância euclidiana entre dois pontos.""" | |
| return np.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2) | |
| def allocate_colors_to_grid(values: list[float], factorx: int, factory: int) -> list[list[int]]: | |
| if len(values) != 4: | |
| raise ValueError("Devem ser exatamente 4 categorias.") | |
| DX = factorx | |
| DY = factory | |
| grid: list[list[int]] = [[-1 for _ in range(DX)] for _ in range(DY)] | |
| available_cells: list[Point] = [Point(i, j) for i in range(DX) for j in range(DY)] | |
| groups: list[Cat] = [] | |
| for i, value in enumerate(values): | |
| qtd=int(value * DX * DY / 100) | |
| cat: Cat = Cat(qtd=qtd, value=i) | |
| groups.append(cat) | |
| # groups[0].corner = (0, 0) # Superior esquerdo | |
| # groups[1].corner = (0, DY - 1) # Superior direito | |
| # groups[2].corner = (DX - 1, 0) # Inferior esquerdo | |
| # groups[3].corner = (DX - 1, DY - 1) # Inferior direito | |
| groups[0].corner = (random.randint(0, DX // 2), random.randint(0, DY // 2)) # Superior esquerdo | |
| groups[1].corner = (random.randint(0, DX // 2), random.randint(DY // 2, DY)) # Superior direito | |
| groups[2].corner = (random.randint(DX // 2, DX), random.randint(0, DY // 2)) # Inferior esquerdo | |
| groups[3].corner = (random.randint(DX // 2, DX), random.randint(DY // 2, DY)) # Inferior direito | |
| # groups[0].corner = (random.randint(0, DX), random.randint(0, DY)) # Superior esquerdo | |
| # groups[1].corner = (random.randint(0, DX), random.randint(0, DY)) # Superior esquerdo | |
| # groups[2].corner = (random.randint(0, DX), random.randint(0, DY)) # Superior esquerdo | |
| # groups[3].corner = (random.randint(0, DX), random.randint(0, DY)) # Superior esquerdo | |
| for i in range(4): | |
| # Gerar pontos ordenados para cada grupo | |
| cat = groups[i] | |
| cat.sorted_points = sorted(available_cells, key=lambda p: get_distance(cat.corner, (p.x, p.y)), reverse=True) | |
| while True: | |
| empty = True | |
| random.shuffle(groups) | |
| for i in range(4): | |
| if groups[i].qtd <= 0: | |
| continue | |
| # Encontrar a célula mais próxima do alvo | |
| while groups[i].sorted_points[-1].free is False: | |
| groups[i].sorted_points.pop() | |
| chosen_point = groups[i].sorted_points[-1] | |
| chosen_point.free = False | |
| grid[chosen_point.y][chosen_point.x] = groups[i].value | |
| groups[i].qtd -= 1 | |
| empty = False | |
| if empty: | |
| break | |
| return grid | |
| # def create_image_from_grid(grid: list[list[int]], colors: list[str], path_to_save: str): | |
| # plt.imshow(grid, cmap=cmap) | |
| # plt.axis('off') # Remove os eixos para uma imagem limpa | |
| # plt.savefig(path_to_save, bbox_inches='tight', pad_inches=0) | |
| # plt.close() # Fecha a figura para liberar memória | |
| def create_image_from_grid(grid: list[list[int]], colors: list[str], path_to_save: str, scale: int = 1): | |
| height = len(grid) | |
| width = len(grid[0]) if height > 0 else 0 | |
| # Cria uma nova imagem RGB | |
| img = Image.new('RGB', (width, height)) | |
| pixels = img.load() | |
| # Preenche os pixels com base no grid e na paleta | |
| for y in range(height): | |
| for x in range(width): | |
| color_hex = colors[grid[y][x]] | |
| pixels[x, y] = tuple(int(color_hex[i:i+2], 16) for i in (1, 3, 5)) # de '#RRGGBB' para (R, G, B) | |
| # Se quiser ampliar a imagem com antialiasing | |
| if scale > 1: | |
| img = img.resize((width * scale, height * scale), resample=Image.NEAREST) | |
| img.save(path_to_save) | |
| def main(): | |
| factorx = 60 | |
| factory = 100 | |
| # values: list[float] = [random.randint(1, 100), random.randint(1, 100), random.randint(1, 100), random.randint(1, 100)] | |
| values: list[float] = [10, 20, 20, 5] | |
| total = sum(values) | |
| for i in range(len(values)): | |
| values[i] = round(values[i] / total * 100) | |
| values[0] += 100 - sum(values) # Ajusta o primeiro valor para garantir que a soma seja 100 | |
| print(f"Valores normalizados: {values}") | |
| grid = allocate_colors_to_grid(values, factorx, factory) | |
| blue = '#0000FF' | |
| green = '#00FF00' | |
| yellow = '#FFFF00' | |
| red = '#FF0000' | |
| create_image_from_grid(grid, [blue, green, yellow, red], 'grid_image.png', 3) | |
| if __name__ == "__main__": | |
| main() |
Author
senapk
commented
Jul 19, 2025
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment