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)
|