Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -168,6 +168,7 @@ def extrair_tabelas_pdf(pdf_path):
|
|
168 |
except Exception as e:
|
169 |
print(f"Erro na extração das tabelas: {str(e)}")
|
170 |
raise
|
|
|
171 |
def obter_disciplinas_validas(df):
|
172 |
"""Identifica disciplinas válidas no boletim com seus dados."""
|
173 |
colunas_notas = ['Nota B1', 'Nota B2', 'Nota B3', 'Nota B4']
|
@@ -351,6 +352,97 @@ def plotar_evolucao_bimestres(disciplinas_dados, temp_dir, titulo=None, nome_arq
|
|
351 |
plt.close()
|
352 |
return plot_path
|
353 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
354 |
def gerar_relatorio_pdf(df, disciplinas_dados, grafico_basica, grafico_diversificada, grafico_medias):
|
355 |
"""Gera relatório PDF com os gráficos e análises."""
|
356 |
pdf = FPDF()
|
|
|
168 |
except Exception as e:
|
169 |
print(f"Erro na extração das tabelas: {str(e)}")
|
170 |
raise
|
171 |
+
|
172 |
def obter_disciplinas_validas(df):
|
173 |
"""Identifica disciplinas válidas no boletim com seus dados."""
|
174 |
colunas_notas = ['Nota B1', 'Nota B2', 'Nota B3', 'Nota B4']
|
|
|
352 |
plt.close()
|
353 |
return plot_path
|
354 |
|
355 |
+
def plotar_graficos_destacados(disciplinas_dados, temp_dir):
|
356 |
+
"""Plota gráficos de médias e frequências com destaques."""
|
357 |
+
n_disciplinas = len(disciplinas_dados)
|
358 |
+
|
359 |
+
if not n_disciplinas:
|
360 |
+
raise ValueError("Nenhuma disciplina válida encontrada no boletim.")
|
361 |
+
|
362 |
+
# Criar figura
|
363 |
+
plt.figure(figsize=(12, 10))
|
364 |
+
|
365 |
+
disciplinas = [d['disciplina'] for d in disciplinas_dados]
|
366 |
+
medias_notas = [d['media_notas'] for d in disciplinas_dados]
|
367 |
+
medias_freq = [d['media_freq'] for d in disciplinas_dados]
|
368 |
+
|
369 |
+
# Criar subplot com mais espaço entre os gráficos
|
370 |
+
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10), height_ratios=[1, 1])
|
371 |
+
plt.subplots_adjust(hspace=0.5) # Aumentar espaço entre os gráficos
|
372 |
+
|
373 |
+
# Definir cores baseadas nos limites de aprovação
|
374 |
+
cores_notas = ['red' if media < LIMITE_APROVACAO_NOTA else '#2ecc71' for media in medias_notas]
|
375 |
+
cores_freq = ['red' if media < LIMITE_APROVACAO_FREQ else '#2ecc71' for media in medias_freq]
|
376 |
+
|
377 |
+
# Calcular médias globais
|
378 |
+
media_global = np.mean(medias_notas)
|
379 |
+
freq_global = np.mean(medias_freq)
|
380 |
+
|
381 |
+
# Gráfico de notas
|
382 |
+
barras_notas = ax1.bar(disciplinas, medias_notas, color=cores_notas)
|
383 |
+
ax1.set_title('Média de Notas por Disciplina', pad=20, fontsize=12, fontweight='bold')
|
384 |
+
ax1.set_ylim(0, ESCALA_MAXIMA_NOTAS)
|
385 |
+
ax1.grid(True, axis='y', alpha=0.3, linestyle='--')
|
386 |
+
|
387 |
+
# Melhorar a apresentação dos rótulos
|
388 |
+
ax1.set_xticklabels(disciplinas, rotation=45, ha='right', va='top')
|
389 |
+
ax1.set_ylabel('Notas', fontsize=10, labelpad=10)
|
390 |
+
|
391 |
+
# Adicionar linha de média mínima
|
392 |
+
ax1.axhline(y=LIMITE_APROVACAO_NOTA, color='r', linestyle='--', alpha=0.3)
|
393 |
+
ax1.text(0.02, LIMITE_APROVACAO_NOTA + 0.1, 'Média mínima (5,0)',
|
394 |
+
transform=ax1.get_yaxis_transform(), color='r', alpha=0.7)
|
395 |
+
|
396 |
+
# Valores nas barras de notas
|
397 |
+
for barra in barras_notas:
|
398 |
+
altura = barra.get_height()
|
399 |
+
ax1.text(barra.get_x() + barra.get_width()/2., altura,
|
400 |
+
f'{altura:.1f}',
|
401 |
+
ha='center', va='bottom', fontsize=8)
|
402 |
+
|
403 |
+
# Gráfico de frequências
|
404 |
+
barras_freq = ax2.bar(disciplinas, medias_freq, color=cores_freq)
|
405 |
+
ax2.set_title('Frequência Média por Disciplina', pad=20, fontsize=12, fontweight='bold')
|
406 |
+
ax2.set_ylim(0, 110)
|
407 |
+
ax2.grid(True, axis='y', alpha=0.3, linestyle='--')
|
408 |
+
|
409 |
+
# Melhorar a apresentação dos rótulos
|
410 |
+
ax2.set_xticklabels(disciplinas, rotation=45, ha='right', va='top')
|
411 |
+
ax2.set_ylabel('Frequência (%)', fontsize=10, labelpad=10)
|
412 |
+
|
413 |
+
# Adicionar linha de frequência mínima
|
414 |
+
ax2.axhline(y=LIMITE_APROVACAO_FREQ, color='r', linestyle='--', alpha=0.3)
|
415 |
+
ax2.text(0.02, LIMITE_APROVACAO_FREQ + 1, 'Frequência mínima (75%)',
|
416 |
+
transform=ax2.get_yaxis_transform(), color='r', alpha=0.7)
|
417 |
+
|
418 |
+
# Valores nas barras de frequência
|
419 |
+
for barra in barras_freq:
|
420 |
+
altura = barra.get_height()
|
421 |
+
ax2.text(barra.get_x() + barra.get_width()/2., altura,
|
422 |
+
f'{altura:.1f}%',
|
423 |
+
ha='center', va='bottom', fontsize=8)
|
424 |
+
|
425 |
+
# Título global com informações de média
|
426 |
+
plt.suptitle(
|
427 |
+
f'Desempenho Geral\nMédia Global: {media_global:.1f} | Frequência Global: {freq_global:.1f}%',
|
428 |
+
y=0.98, fontsize=14, fontweight='bold'
|
429 |
+
)
|
430 |
+
|
431 |
+
# Aviso de risco de reprovação se necessário
|
432 |
+
if freq_global < LIMITE_APROVACAO_FREQ:
|
433 |
+
plt.figtext(0.5, 0.02,
|
434 |
+
"Atenção: Risco de Reprovação por Baixa Frequência",
|
435 |
+
ha="center", fontsize=11, color="red", weight='bold')
|
436 |
+
|
437 |
+
plt.tight_layout()
|
438 |
+
|
439 |
+
# Salvar o gráfico
|
440 |
+
plot_path = os.path.join(temp_dir, 'medias_frequencias.png')
|
441 |
+
plt.savefig(plot_path, bbox_inches='tight', dpi=300)
|
442 |
+
plt.close()
|
443 |
+
|
444 |
+
return plot_path
|
445 |
+
|
446 |
def gerar_relatorio_pdf(df, disciplinas_dados, grafico_basica, grafico_diversificada, grafico_medias):
|
447 |
"""Gera relatório PDF com os gráficos e análises."""
|
448 |
pdf = FPDF()
|