Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -425,6 +425,126 @@ def plotar_evolucao_bimestres(disciplinas_dados: List[Dict], temp_dir: str,
|
|
425 |
|
426 |
return plot_path
|
427 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
428 |
edgecolor='none',
|
429 |
alpha=0.8,
|
430 |
pad=5,
|
@@ -461,6 +581,7 @@ def plotar_evolucao_bimestres(disciplinas_dados: List[Dict], temp_dir: str,
|
|
461 |
|
462 |
return plot_path
|
463 |
|
|
|
464 |
# Funções de processamento do PDF e geração de relatórios
|
465 |
def gerar_relatorio_pdf(df: pd.DataFrame, disciplinas_dados: List[Dict],
|
466 |
grafico_basica: str, grafico_diversificada: str,
|
|
|
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)
|
431 |
+
|
432 |
+
if not n_disciplinas:
|
433 |
+
raise ValueError("Nenhuma disciplina válida encontrada no boletim.")
|
434 |
+
|
435 |
+
# Configuração do estilo
|
436 |
+
plt.style.use('seaborn')
|
437 |
+
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10),
|
438 |
+
height_ratios=[1, 1])
|
439 |
+
plt.subplots_adjust(hspace=0.4)
|
440 |
+
|
441 |
+
disciplinas = [d['disciplina'] for d in disciplinas_dados]
|
442 |
+
medias_notas = [d['media_notas'] for d in disciplinas_dados]
|
443 |
+
medias_freq = [d['media_freq'] for d in disciplinas_dados]
|
444 |
+
|
445 |
+
# Definir cores baseadas nos limites
|
446 |
+
cores_notas = [COR_REPROVADO if media < LIMITE_APROVACAO_NOTA
|
447 |
+
else COR_APROVADO for media in medias_notas]
|
448 |
+
cores_freq = [COR_REPROVADO if media < LIMITE_APROVACAO_FREQ
|
449 |
+
else COR_APROVADO for media in medias_freq]
|
450 |
+
|
451 |
+
# Calcular médias globais
|
452 |
+
media_global = np.mean(medias_notas)
|
453 |
+
freq_global = np.mean(medias_freq)
|
454 |
+
|
455 |
+
# Configurações comuns para os eixos
|
456 |
+
for ax in [ax1, ax2]:
|
457 |
+
ax.grid(True, axis='y', alpha=0.2, linestyle='--')
|
458 |
+
ax.set_axisbelow(True)
|
459 |
+
ax.spines['top'].set_visible(False)
|
460 |
+
ax.spines['right'].set_visible(False)
|
461 |
+
|
462 |
+
# Gráfico de notas
|
463 |
+
barras_notas = ax1.bar(disciplinas, medias_notas, color=cores_notas)
|
464 |
+
ax1.set_title('Média de Notas por Disciplina',
|
465 |
+
pad=20, fontsize=14, fontweight='bold')
|
466 |
+
ax1.set_ylim(0, ESCALA_MAXIMA_NOTAS)
|
467 |
+
ax1.set_xticklabels(disciplinas, rotation=45,
|
468 |
+
ha='right', va='top', fontsize=10)
|
469 |
+
ax1.set_ylabel('Notas', fontsize=12, labelpad=10)
|
470 |
+
|
471 |
+
# Linha de média mínima
|
472 |
+
ax1.axhline(y=LIMITE_APROVACAO_NOTA,
|
473 |
+
color=COR_REPROVADO,
|
474 |
+
linestyle='--',
|
475 |
+
alpha=0.3,
|
476 |
+
linewidth=2)
|
477 |
+
ax1.text(0.02, LIMITE_APROVACAO_NOTA + 0.1,
|
478 |
+
'Média mínima (5,0)',
|
479 |
+
transform=ax1.get_yaxis_transform(),
|
480 |
+
color=COR_REPROVADO,
|
481 |
+
alpha=0.7,
|
482 |
+
fontsize=10)
|
483 |
+
|
484 |
+
# Valores nas barras de notas
|
485 |
+
for barra in barras_notas:
|
486 |
+
altura = barra.get_height()
|
487 |
+
cor_texto = 'white' if altura >= LIMITE_APROVACAO_NOTA else 'black'
|
488 |
+
ax1.text(barra.get_x() + barra.get_width()/2., altura,
|
489 |
+
f'{altura:.1f}',
|
490 |
+
ha='center',
|
491 |
+
va='bottom',
|
492 |
+
fontsize=10,
|
493 |
+
bbox=dict(
|
494 |
+
facecolor='white',
|
495 |
+
edgecolor='none',
|
496 |
+
alpha=0.7,
|
497 |
+
pad=1
|
498 |
+
),
|
499 |
+
color=cor_texto if altura >= 8 else 'black')
|
500 |
+
|
501 |
+
# Gráfico de frequências
|
502 |
+
barras_freq = ax2.bar(disciplinas, medias_freq, color=cores_freq)
|
503 |
+
ax2.set_title('Frequência Média por Disciplina',
|
504 |
+
pad=20, fontsize=14, fontweight='bold')
|
505 |
+
ax2.set_ylim(0, 110)
|
506 |
+
ax2.set_xticklabels(disciplinas, rotation=45,
|
507 |
+
ha='right', va='top', fontsize=10)
|
508 |
+
ax2.set_ylabel('Frequência (%)', fontsize=12, labelpad=10)
|
509 |
+
|
510 |
+
# Linha de frequência mínima
|
511 |
+
ax2.axhline(y=LIMITE_APROVACAO_FREQ,
|
512 |
+
color=COR_REPROVADO,
|
513 |
+
linestyle='--',
|
514 |
+
alpha=0.3,
|
515 |
+
linewidth=2)
|
516 |
+
ax2.text(0.02, LIMITE_APROVACAO_FREQ + 1,
|
517 |
+
'Frequência mínima (75%)',
|
518 |
+
transform=ax2.get_yaxis_transform(),
|
519 |
+
color=COR_REPROVADO,
|
520 |
+
alpha=0.7,
|
521 |
+
fontsize=10)
|
522 |
+
|
523 |
+
# Valores nas barras de frequência
|
524 |
+
for barra in barras_freq:
|
525 |
+
altura = barra.get_height()
|
526 |
+
cor_texto = 'white' if altura >= LIMITE_APROVACAO_FREQ else 'black'
|
527 |
+
ax2.text(barra.get_x() + barra.get_width()/2., altura,
|
528 |
+
f'{altura:.1f}%',
|
529 |
+
ha='center',
|
530 |
+
va='bottom',
|
531 |
+
fontsize=10,
|
532 |
+
bbox=dict(
|
533 |
+
facecolor='white',
|
534 |
+
edgecolor='none',
|
535 |
+
alpha=0.7,
|
536 |
+
pad=1
|
537 |
+
),
|
538 |
+
color=cor_texto if altura >= 90 else 'black')
|
539 |
+
|
540 |
+
# Título global com estilo
|
541 |
+
plt.suptitle(
|
542 |
+
f'Desempenho Geral\nMédia Global: {media_global:.1f} | Frequência Global: {freq_global:.1f}%',
|
543 |
+
y=0.98,
|
544 |
+
fontsize=16,
|
545 |
+
fontweight='bold',
|
546 |
+
bbox=dict(
|
547 |
+
facecolor='white',
|
548 |
edgecolor='none',
|
549 |
alpha=0.8,
|
550 |
pad=5,
|
|
|
581 |
|
582 |
return plot_path
|
583 |
|
584 |
+
|
585 |
# Funções de processamento do PDF e geração de relatórios
|
586 |
def gerar_relatorio_pdf(df: pd.DataFrame, disciplinas_dados: List[Dict],
|
587 |
grafico_basica: str, grafico_diversificada: str,
|