Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -311,120 +311,100 @@ def plotar_evolucao_bimestres(disciplinas_dados: List[Dict], temp_dir: str,
|
|
| 311 |
raise ValueError("Nenhuma disciplina válida encontrada para plotar.")
|
| 312 |
|
| 313 |
# Configuração do estilo
|
| 314 |
-
plt.style.use('seaborn-v0_8-darkgrid')
|
| 315 |
fig, ax = plt.subplots(figsize=(11.69, 8.27))
|
| 316 |
|
| 317 |
# Configurar grid mais suave
|
| 318 |
ax.grid(True, linestyle='--', alpha=0.2, color='gray')
|
| 319 |
ax.set_axisbelow(True)
|
| 320 |
|
| 321 |
-
# Paleta de cores e outros parâmetros de estilo
|
| 322 |
cores = gerar_paleta_cores(n_disciplinas)
|
| 323 |
marcadores = ['o', 's', '^', 'D', 'v', '<', '>', 'p']
|
| 324 |
estilos_linha = ['-', '--', '-.', ':']
|
|
|
|
| 325 |
deslocamentos = np.linspace(-0.02, 0.02, n_disciplinas)
|
| 326 |
anotacoes_usadas = {}
|
| 327 |
-
|
| 328 |
for idx, disc_data in enumerate(disciplinas_dados):
|
| 329 |
notas = pd.Series(disc_data['notas'])
|
| 330 |
bimestres_cursados = disc_data['bimestres_cursados']
|
| 331 |
desloc = deslocamentos[idx]
|
| 332 |
|
| 333 |
if bimestres_cursados:
|
| 334 |
-
notas_validas = [nota for i, nota in enumerate(notas, 1)
|
| 335 |
-
|
| 336 |
-
bimestres = [bim for bim in bimestres_cursados
|
| 337 |
-
if notas[bim-1] is not None]
|
| 338 |
bimestres_deslocados = [bim + desloc for bim in bimestres]
|
| 339 |
|
| 340 |
if notas_validas:
|
| 341 |
-
# Linha com sombreamento
|
| 342 |
plt.plot(bimestres_deslocados, notas_validas,
|
| 343 |
-
|
| 344 |
-
|
| 345 |
-
|
| 346 |
-
|
| 347 |
-
|
| 348 |
-
|
| 349 |
-
|
| 350 |
-
|
| 351 |
|
| 352 |
-
# Área sombreada sob a linha
|
| 353 |
plt.fill_between(bimestres_deslocados, 0, notas_validas,
|
| 354 |
-
|
| 355 |
-
alpha=0.1)
|
| 356 |
|
| 357 |
-
# Anotações das notas
|
| 358 |
for bim, nota in zip(bimestres_deslocados, notas_validas):
|
| 359 |
if nota is not None:
|
| 360 |
y_offset = 10
|
| 361 |
-
while any(abs(y - (nota + y_offset/20)) < 0.4
|
| 362 |
-
for y, _ in anotacoes_usadas.get(bim, [])):
|
| 363 |
y_offset += 5
|
| 364 |
|
| 365 |
plt.annotate(f"{nota:.1f}",
|
| 366 |
-
|
| 367 |
-
|
| 368 |
-
|
| 369 |
-
|
| 370 |
-
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
|
| 374 |
-
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
boxstyle='round,pad=0.5'
|
| 378 |
-
))
|
| 379 |
|
| 380 |
if bim not in anotacoes_usadas:
|
| 381 |
anotacoes_usadas[bim] = []
|
| 382 |
anotacoes_usadas[bim].append((nota + y_offset/20, nota))
|
| 383 |
|
| 384 |
-
# Estilização do gráfico
|
| 385 |
titulo_grafico = titulo or 'Evolução das Médias por Disciplina'
|
| 386 |
plt.title(titulo_grafico, pad=20, fontsize=14, fontweight='bold')
|
| 387 |
plt.xlabel('Bimestres', fontsize=12, labelpad=10)
|
| 388 |
plt.ylabel('Notas', fontsize=12, labelpad=10)
|
| 389 |
|
| 390 |
-
# Remover bordas desnecessárias
|
| 391 |
ax.spines['top'].set_visible(False)
|
| 392 |
ax.spines['right'].set_visible(False)
|
| 393 |
|
| 394 |
-
plt.xticks([1, 2, 3, 4], ['1º Bim', '2º Bim', '3º Bim', '4º Bim'],
|
| 395 |
-
fontsize=10)
|
| 396 |
plt.ylim(0, ESCALA_MAXIMA_NOTAS)
|
| 397 |
|
| 398 |
-
|
| 399 |
-
plt.
|
| 400 |
-
|
| 401 |
-
plt.text(0.02, LIMITE_APROVACAO_NOTA + 0.1,
|
| 402 |
-
'Média mínima para aprovação',
|
| 403 |
-
transform=plt.gca().get_yaxis_transform(),
|
| 404 |
-
color=COR_REPROVADO, alpha=0.7)
|
| 405 |
|
| 406 |
-
# Legenda
|
| 407 |
if n_disciplinas > 8:
|
| 408 |
-
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left',
|
| 409 |
-
|
| 410 |
-
fancybox=True, shadow=True,
|
| 411 |
-
ncol=max(1, n_disciplinas // 12))
|
| 412 |
else:
|
| 413 |
-
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left',
|
| 414 |
-
fontsize=10, framealpha=0.8,
|
| 415 |
-
fancybox=True, shadow=True)
|
| 416 |
|
| 417 |
plt.tight_layout()
|
|
|
|
|
|
|
|
|
|
| 418 |
|
| 419 |
-
# Salvar
|
| 420 |
nome_arquivo = nome_arquivo or 'evolucao_notas.png'
|
| 421 |
plot_path = os.path.join(temp_dir, nome_arquivo)
|
| 422 |
-
plt.savefig(plot_path, bbox_inches='tight', dpi=300,
|
| 423 |
-
facecolor='white', edgecolor='none')
|
| 424 |
plt.close()
|
| 425 |
|
| 426 |
return plot_path
|
| 427 |
-
|
| 428 |
def plotar_graficos_destacados(disciplinas_dados: List[Dict], temp_dir: str) -> str:
|
| 429 |
"""Plota gráficos de médias e frequências com visual aprimorado."""
|
| 430 |
n_disciplinas = len(disciplinas_dados)
|
|
|
|
| 311 |
raise ValueError("Nenhuma disciplina válida encontrada para plotar.")
|
| 312 |
|
| 313 |
# Configuração do estilo
|
| 314 |
+
plt.style.use('seaborn-v0_8-darkgrid')
|
| 315 |
fig, ax = plt.subplots(figsize=(11.69, 8.27))
|
| 316 |
|
| 317 |
# Configurar grid mais suave
|
| 318 |
ax.grid(True, linestyle='--', alpha=0.2, color='gray')
|
| 319 |
ax.set_axisbelow(True)
|
| 320 |
|
|
|
|
| 321 |
cores = gerar_paleta_cores(n_disciplinas)
|
| 322 |
marcadores = ['o', 's', '^', 'D', 'v', '<', '>', 'p']
|
| 323 |
estilos_linha = ['-', '--', '-.', ':']
|
| 324 |
+
|
| 325 |
deslocamentos = np.linspace(-0.02, 0.02, n_disciplinas)
|
| 326 |
anotacoes_usadas = {}
|
| 327 |
+
|
| 328 |
for idx, disc_data in enumerate(disciplinas_dados):
|
| 329 |
notas = pd.Series(disc_data['notas'])
|
| 330 |
bimestres_cursados = disc_data['bimestres_cursados']
|
| 331 |
desloc = deslocamentos[idx]
|
| 332 |
|
| 333 |
if bimestres_cursados:
|
| 334 |
+
notas_validas = [nota for i, nota in enumerate(notas, 1) if i in bimestres_cursados and nota is not None]
|
| 335 |
+
bimestres = [bim for bim in bimestres_cursados if notas[bim-1] is not None]
|
|
|
|
|
|
|
| 336 |
bimestres_deslocados = [bim + desloc for bim in bimestres]
|
| 337 |
|
| 338 |
if notas_validas:
|
|
|
|
| 339 |
plt.plot(bimestres_deslocados, notas_validas,
|
| 340 |
+
color=cores[idx % len(cores)],
|
| 341 |
+
marker=marcadores[idx % len(marcadores)],
|
| 342 |
+
markersize=8,
|
| 343 |
+
linewidth=2.5,
|
| 344 |
+
label=disc_data['disciplina'],
|
| 345 |
+
linestyle=estilos_linha[idx % len(estilos_linha)],
|
| 346 |
+
alpha=0.8,
|
| 347 |
+
zorder=3)
|
| 348 |
|
|
|
|
| 349 |
plt.fill_between(bimestres_deslocados, 0, notas_validas,
|
| 350 |
+
color=cores[idx % len(cores)], alpha=0.1)
|
|
|
|
| 351 |
|
|
|
|
| 352 |
for bim, nota in zip(bimestres_deslocados, notas_validas):
|
| 353 |
if nota is not None:
|
| 354 |
y_offset = 10
|
| 355 |
+
while any(abs(y - (nota + y_offset/20)) < 0.4 for y, _ in anotacoes_usadas.get(bim, [])):
|
|
|
|
| 356 |
y_offset += 5
|
| 357 |
|
| 358 |
plt.annotate(f"{nota:.1f}",
|
| 359 |
+
(bim, nota),
|
| 360 |
+
xytext=(0, y_offset),
|
| 361 |
+
textcoords="offset points",
|
| 362 |
+
ha='center',
|
| 363 |
+
va='bottom',
|
| 364 |
+
fontsize=9,
|
| 365 |
+
bbox=dict(facecolor='white',
|
| 366 |
+
edgecolor=cores[idx % len(cores)],
|
| 367 |
+
alpha=0.8,
|
| 368 |
+
pad=2,
|
| 369 |
+
boxstyle='round,pad=0.5'))
|
|
|
|
|
|
|
| 370 |
|
| 371 |
if bim not in anotacoes_usadas:
|
| 372 |
anotacoes_usadas[bim] = []
|
| 373 |
anotacoes_usadas[bim].append((nota + y_offset/20, nota))
|
| 374 |
|
|
|
|
| 375 |
titulo_grafico = titulo or 'Evolução das Médias por Disciplina'
|
| 376 |
plt.title(titulo_grafico, pad=20, fontsize=14, fontweight='bold')
|
| 377 |
plt.xlabel('Bimestres', fontsize=12, labelpad=10)
|
| 378 |
plt.ylabel('Notas', fontsize=12, labelpad=10)
|
| 379 |
|
|
|
|
| 380 |
ax.spines['top'].set_visible(False)
|
| 381 |
ax.spines['right'].set_visible(False)
|
| 382 |
|
| 383 |
+
plt.xticks([1, 2, 3, 4], ['1º Bim', '2º Bim', '3º Bim', '4º Bim'], fontsize=10)
|
|
|
|
| 384 |
plt.ylim(0, ESCALA_MAXIMA_NOTAS)
|
| 385 |
|
| 386 |
+
plt.axhline(y=LIMITE_APROVACAO_NOTA, color=COR_REPROVADO, linestyle='--', alpha=0.3, linewidth=2)
|
| 387 |
+
plt.text(0.02, LIMITE_APROVACAO_NOTA + 0.1, 'Média mínima para aprovação',
|
| 388 |
+
transform=plt.gca().get_yaxis_transform(), color=COR_REPROVADO, alpha=0.7)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 389 |
|
|
|
|
| 390 |
if n_disciplinas > 8:
|
| 391 |
+
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', fontsize=9, framealpha=0.8, fancybox=True, shadow=True,
|
| 392 |
+
ncol=max(1, n_disciplinas // 12))
|
|
|
|
|
|
|
| 393 |
else:
|
| 394 |
+
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', fontsize=10, framealpha=0.8, fancybox=True, shadow=True)
|
|
|
|
|
|
|
| 395 |
|
| 396 |
plt.tight_layout()
|
| 397 |
+
|
| 398 |
+
# Força a renderização para evitar o erro de renderizador
|
| 399 |
+
fig.canvas.draw()
|
| 400 |
|
| 401 |
+
# Salvar com alta qualidade
|
| 402 |
nome_arquivo = nome_arquivo or 'evolucao_notas.png'
|
| 403 |
plot_path = os.path.join(temp_dir, nome_arquivo)
|
| 404 |
+
plt.savefig(plot_path, bbox_inches='tight', dpi=300, facecolor='white', edgecolor='none')
|
|
|
|
| 405 |
plt.close()
|
| 406 |
|
| 407 |
return plot_path
|
|
|
|
| 408 |
def plotar_graficos_destacados(disciplinas_dados: List[Dict], temp_dir: str) -> str:
|
| 409 |
"""Plota gráficos de médias e frequências com visual aprimorado."""
|
| 410 |
n_disciplinas = len(disciplinas_dados)
|