histlearn commited on
Commit
1f36773
·
verified ·
1 Parent(s): 52fdf78

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +24 -33
app.py CHANGED
@@ -270,7 +270,7 @@ class ReportGenerator:
270
  """Cria o gráfico de relação entre tempo e acertos com visualização otimizada."""
271
  plt.figure(figsize=(15, 10))
272
  ax = plt.gca()
273
-
274
  # Configuração inicial
275
  plt.grid(True, alpha=0.2, linestyle='--')
276
  ax.set_facecolor('#f8f9fa')
@@ -278,24 +278,18 @@ class ReportGenerator:
278
  def calculate_distance(p1, p2):
279
  return np.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)
280
 
281
- def create_bezier_curve(start, end):
282
- mid_x = (start[0] + end[0]) / 2
283
- return f'M{start[0]},{start[1]} ' \
284
- f'C{mid_x},{start[1]} {mid_x},{end[1]} {end[0]},{end[1]}'
285
-
286
  # Estruturas para armazenamento
287
  points_by_level = {level: [] for level in self.colors.keys()}
288
  label_positions = {}
289
- connection_lines = []
290
 
291
  # Coletar pontos por nível
292
  for nivel, color in self.colors.items():
293
  mask = self.data['Nível'] == nivel
294
  tempo = pd.to_timedelta(self.data[mask]['Total Tempo']).dt.total_seconds() / 60
295
  acertos = self.data[mask]['Acertos Absolutos']
296
-
297
  plt.scatter(tempo, acertos, c=color, label=nivel, alpha=0.7, s=100)
298
-
299
  for t, a, nome in zip(tempo, acertos, self.data[mask]['Nome do Aluno']):
300
  points_by_level[nivel].append((t, a, nome))
301
 
@@ -304,36 +298,36 @@ class ReportGenerator:
304
  plt.axhline(y=media_acertos, color='gray', linestyle=':', alpha=0.5,
305
  label='Média de Acertos')
306
 
307
- # Processamento por nível para evitar sobreposições entre grupos
308
  for nivel, points in points_by_level.items():
309
- # Ordenar pontos por Y para agrupar melhor
310
  points.sort(key=lambda p: (p[1], p[0]))
311
-
312
  # Agrupar pontos próximos
313
  groups = []
314
  used = set()
315
-
316
  for i, p1 in enumerate(points):
317
  if i in used:
318
  continue
319
-
320
  current_group = [p1]
321
  used.add(i)
322
-
323
  for j, p2 in enumerate(points):
324
  if j not in used and calculate_distance(p1[:2], p2[:2]) < 2.0:
325
  current_group.append(p2)
326
  used.add(j)
327
-
328
  groups.append(current_group)
329
 
330
  # Processar cada grupo
331
  for group in groups:
332
- # Calcular centroide do grupo
333
  center_x = sum(p[0] for p in group) / len(group)
334
  center_y = sum(p[1] for p in group) / len(group)
335
-
336
- # Determinar posição do label
337
  if len(group) == 1:
338
  x, y, nome = group[0]
339
  label_text = nome.split()[0]
@@ -341,14 +335,14 @@ class ReportGenerator:
341
  x, y = center_x, center_y
342
  label_text = '\n'.join(sorted(p[2].split()[0] for p in group))
343
 
344
- # Calcular posição otimizada para o label
345
  angle = np.random.uniform(0, 2*np.pi)
346
  base_radius = 3.0 + len(group) * 0.5
347
-
348
  label_x = x + base_radius * np.cos(angle)
349
  label_y = y + base_radius * np.sin(angle)
350
-
351
- # Ajustar posição se muito próxima de outros labels
352
  while any(calculate_distance((label_x, label_y), pos) < 2.0
353
  for pos in label_positions.values()):
354
  angle += np.pi/4
@@ -357,8 +351,8 @@ class ReportGenerator:
357
 
358
  # Guardar posição do label
359
  label_positions[(x, y)] = (label_x, label_y)
360
-
361
- # Criar anotação com curva Bezier
362
  plt.annotate(
363
  label_text,
364
  (x, y),
@@ -374,27 +368,24 @@ class ReportGenerator:
374
  fontsize=9,
375
  arrowprops=dict(
376
  arrowstyle='-|>',
377
- connectionstyle=f'path,{create_bezier_curve((x,y), (label_x,label_y))}',
378
  color='gray',
379
  alpha=0.6,
380
  mutation_scale=15
381
  )
382
  )
383
-
384
- # Registrar linha de conexão
385
- connection_lines.append(((x, y), (label_x, label_y)))
386
 
387
  # Configurações finais
388
  plt.title('Relação entre Tempo e Acertos por Nível', pad=20, fontsize=14)
389
  plt.xlabel('Tempo Total (minutos)', fontsize=12)
390
  plt.ylabel('Número de Acertos', fontsize=12)
391
-
392
- # Ajustar limites com margens
393
  x_min, x_max = plt.xlim()
394
  y_min, y_max = plt.ylim()
395
  plt.xlim(x_min - 1, x_max + 1)
396
  plt.ylim(max(0, y_min - 1), y_max + 1)
397
-
398
  # Legenda
399
  handles, labels = plt.gca().get_legend_handles_labels()
400
  by_label = dict(zip(labels, handles))
@@ -407,7 +398,7 @@ class ReportGenerator:
407
  frameon=True,
408
  fancybox=True
409
  )
410
-
411
  plt.tight_layout()
412
  return plt.gcf()
413
 
 
270
  """Cria o gráfico de relação entre tempo e acertos com visualização otimizada."""
271
  plt.figure(figsize=(15, 10))
272
  ax = plt.gca()
273
+
274
  # Configuração inicial
275
  plt.grid(True, alpha=0.2, linestyle='--')
276
  ax.set_facecolor('#f8f9fa')
 
278
  def calculate_distance(p1, p2):
279
  return np.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2)
280
 
 
 
 
 
 
281
  # Estruturas para armazenamento
282
  points_by_level = {level: [] for level in self.colors.keys()}
283
  label_positions = {}
 
284
 
285
  # Coletar pontos por nível
286
  for nivel, color in self.colors.items():
287
  mask = self.data['Nível'] == nivel
288
  tempo = pd.to_timedelta(self.data[mask]['Total Tempo']).dt.total_seconds() / 60
289
  acertos = self.data[mask]['Acertos Absolutos']
290
+
291
  plt.scatter(tempo, acertos, c=color, label=nivel, alpha=0.7, s=100)
292
+
293
  for t, a, nome in zip(tempo, acertos, self.data[mask]['Nome do Aluno']):
294
  points_by_level[nivel].append((t, a, nome))
295
 
 
298
  plt.axhline(y=media_acertos, color='gray', linestyle=':', alpha=0.5,
299
  label='Média de Acertos')
300
 
301
+ # Processamento por nível
302
  for nivel, points in points_by_level.items():
303
+ # Ordenar pontos por Y
304
  points.sort(key=lambda p: (p[1], p[0]))
305
+
306
  # Agrupar pontos próximos
307
  groups = []
308
  used = set()
309
+
310
  for i, p1 in enumerate(points):
311
  if i in used:
312
  continue
313
+
314
  current_group = [p1]
315
  used.add(i)
316
+
317
  for j, p2 in enumerate(points):
318
  if j not in used and calculate_distance(p1[:2], p2[:2]) < 2.0:
319
  current_group.append(p2)
320
  used.add(j)
321
+
322
  groups.append(current_group)
323
 
324
  # Processar cada grupo
325
  for group in groups:
326
+ # Calcular centroide
327
  center_x = sum(p[0] for p in group) / len(group)
328
  center_y = sum(p[1] for p in group) / len(group)
329
+
330
+ # Determinar texto do label
331
  if len(group) == 1:
332
  x, y, nome = group[0]
333
  label_text = nome.split()[0]
 
335
  x, y = center_x, center_y
336
  label_text = '\n'.join(sorted(p[2].split()[0] for p in group))
337
 
338
+ # Calcular posição do label
339
  angle = np.random.uniform(0, 2*np.pi)
340
  base_radius = 3.0 + len(group) * 0.5
341
+
342
  label_x = x + base_radius * np.cos(angle)
343
  label_y = y + base_radius * np.sin(angle)
344
+
345
+ # Ajustar posição se próxima de outros labels
346
  while any(calculate_distance((label_x, label_y), pos) < 2.0
347
  for pos in label_positions.values()):
348
  angle += np.pi/4
 
351
 
352
  # Guardar posição do label
353
  label_positions[(x, y)] = (label_x, label_y)
354
+
355
+ # Criar anotação com estilo de conexão padrão
356
  plt.annotate(
357
  label_text,
358
  (x, y),
 
368
  fontsize=9,
369
  arrowprops=dict(
370
  arrowstyle='-|>',
371
+ connectionstyle='arc3,rad=0.2', # Usando estilo de conexão padrão
372
  color='gray',
373
  alpha=0.6,
374
  mutation_scale=15
375
  )
376
  )
 
 
 
377
 
378
  # Configurações finais
379
  plt.title('Relação entre Tempo e Acertos por Nível', pad=20, fontsize=14)
380
  plt.xlabel('Tempo Total (minutos)', fontsize=12)
381
  plt.ylabel('Número de Acertos', fontsize=12)
382
+
383
+ # Ajustar limites
384
  x_min, x_max = plt.xlim()
385
  y_min, y_max = plt.ylim()
386
  plt.xlim(x_min - 1, x_max + 1)
387
  plt.ylim(max(0, y_min - 1), y_max + 1)
388
+
389
  # Legenda
390
  handles, labels = plt.gca().get_legend_handles_labels()
391
  by_label = dict(zip(labels, handles))
 
398
  frameon=True,
399
  fancybox=True
400
  )
401
+
402
  plt.tight_layout()
403
  return plt.gcf()
404