histlearn commited on
Commit
1586794
·
verified ·
1 Parent(s): 3a8db2a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +121 -0
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,