histlearn commited on
Commit
533ca79
·
verified ·
1 Parent(s): 823bda9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +98 -44
app.py CHANGED
@@ -131,10 +131,21 @@ class ReportGenerator:
131
  def __init__(self, data: pd.DataFrame):
132
  self.data = data
133
  self.stats = self.calculate_statistics()
 
 
 
 
 
 
 
 
 
 
 
134
 
135
  def calculate_statistics(self) -> Dict:
136
- """Calcula estatísticas gerais da turma."""
137
- return {
138
  'media_acertos': float(self.data['Média de Acertos'].str.rstrip('%').astype(float).mean()),
139
  'desvio_padrao': float(self.data['Média de Acertos'].str.rstrip('%').astype(float).std()),
140
  'mediana_acertos': float(self.data['Média de Acertos'].str.rstrip('%').astype(float).median()),
@@ -143,38 +154,68 @@ class ReportGenerator:
143
  'media_tempo': str(pd.to_timedelta(self.data['Total Tempo']).mean())
144
  }
145
 
 
 
 
 
 
 
 
 
 
 
146
  def generate_graphs(self) -> List[plt.Figure]:
147
  """Gera gráficos para o relatório."""
148
  graphs = []
149
 
150
- # Distribuição de notas
151
- plt.figure(figsize=(10, 6))
152
- acertos_data = pd.Series(self.data['Média de Acertos']).str.rstrip('%').astype(float)
153
- sns.histplot(data=acertos_data, bins=10)
154
- plt.axvline(self.stats['media_acertos'], color='r', linestyle='--',
155
- label=f'Média ({self.stats["media_acertos"]:.1f}%)')
156
- plt.title('Distribuição das Notas')
157
- plt.xlabel('Percentual de Acertos')
 
 
 
158
  plt.ylabel('Número de Alunos')
159
- plt.legend()
160
  graphs.append(plt.gcf())
161
  plt.close()
162
 
163
- # Relação tempo x desempenho
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  plt.figure(figsize=(10, 6))
165
- tempo_segundos = pd.to_timedelta(self.data['Total Tempo']).dt.total_seconds()
166
- acertos = pd.Series(self.data['Média de Acertos']).str.rstrip('%').astype(float)
167
- plt.scatter(tempo_segundos / 60, acertos)
168
- plt.title('Tempo x Desempenho')
 
 
 
169
  plt.xlabel('Tempo Total (minutos)')
170
  plt.ylabel('Percentual de Acertos')
 
 
171
  graphs.append(plt.gcf())
172
  plt.close()
173
 
174
  return graphs
175
 
176
  def generate_pdf(self, output_path: str, graphs: List[plt.Figure]) -> None:
177
- """Gera relatório em PDF."""
178
  class PDF(FPDF):
179
  def header(self):
180
  self.set_font('Arial', 'B', 15)
@@ -190,17 +231,27 @@ class ReportGenerator:
190
  pdf.set_font('Arial', '', 10)
191
 
192
  summary_text = f"""
193
- Análise da Turma:
194
  - Média de Acertos: {self.stats['media_acertos']:.1f}%
195
  - Desvio Padrão: {self.stats['desvio_padrao']:.1f}%
196
  - Mediana: {self.stats['mediana_acertos']:.1f}%
197
- - Número de Alunos: {self.stats['total_alunos']}
198
- - Média de Tarefas por Aluno: {self.stats['media_tarefas']:.1f}
199
- - Tempo Médio Total: {self.stats['media_tempo']}
 
200
  """
201
  pdf.multi_cell(0, 10, summary_text)
202
 
203
- # Gráficos
 
 
 
 
 
 
 
 
 
204
  for i, graph in enumerate(graphs):
205
  pdf.add_page()
206
  graph_path = f'temp_graph_{i}.png'
@@ -208,28 +259,31 @@ class ReportGenerator:
208
  pdf.image(graph_path, x=10, y=30, w=270)
209
  os.remove(graph_path)
210
 
211
- # Tabela de alunos
212
- pdf.add_page()
213
- pdf.set_font('Arial', 'B', 12)
214
- pdf.cell(0, 10, 'Desempenho Individual', 0, 1)
215
-
216
- # Cabeçalhos
217
- columns = ['Nome do Aluno', 'Média de Acertos', 'Tarefas', 'Tempo Total', 'Eficiência']
218
- widths = [80, 30, 30, 30, 30]
219
- pdf.set_font('Arial', 'B', 8)
220
- for i, col in enumerate(columns):
221
- pdf.cell(widths[i], 7, col, 1)
222
- pdf.ln()
223
-
224
- # Dados
225
- pdf.set_font('Arial', '', 8)
226
- for _, row in self.data.iterrows():
227
- pdf.cell(widths[0], 6, str(row['Nome do Aluno'])[:40], 1)
228
- pdf.cell(widths[1], 6, str(row['Média de Acertos']), 1)
229
- pdf.cell(widths[2], 6, str(row['Tarefas Completadas']), 1)
230
- pdf.cell(widths[3], 6, str(row['Total Tempo']), 1)
231
- pdf.cell(widths[4], 6, str(row['Eficiência']), 1)
232
- pdf.ln()
 
 
 
233
 
234
  pdf.output(output_path)
235
 
 
131
  def __init__(self, data: pd.DataFrame):
132
  self.data = data
133
  self.stats = self.calculate_statistics()
134
+ # Classificar alunos por níveis
135
+ self.data['Nível'] = self.data['Média de Acertos'].str.rstrip('%').astype(float).apply(self.classify_performance)
136
+ self.data = self.data.sort_values('Média de Acertos'.str.rstrip('%').astype(float), ascending=False)
137
+
138
+ def classify_performance(self, score):
139
+ if score >= 70:
140
+ return 'Avançado'
141
+ elif score >= 40:
142
+ return 'Intermediário'
143
+ else:
144
+ return 'Necessita Atenção'
145
 
146
  def calculate_statistics(self) -> Dict:
147
+ """Calcula estatísticas gerais e por grupo."""
148
+ basic_stats = {
149
  'media_acertos': float(self.data['Média de Acertos'].str.rstrip('%').astype(float).mean()),
150
  'desvio_padrao': float(self.data['Média de Acertos'].str.rstrip('%').astype(float).std()),
151
  'mediana_acertos': float(self.data['Média de Acertos'].str.rstrip('%').astype(float).median()),
 
154
  'media_tempo': str(pd.to_timedelta(self.data['Total Tempo']).mean())
155
  }
156
 
157
+ # Top performers
158
+ top_students = self.data.nlargest(3, 'Média de Acertos')
159
+ basic_stats['top_performers'] = top_students[['Nome do Aluno', 'Média de Acertos']].values.tolist()
160
+
161
+ # Mais eficientes (melhor relação acerto/tempo)
162
+ efficient_students = self.data.nlargest(3, 'Eficiência')
163
+ basic_stats['most_efficient'] = efficient_students[['Nome do Aluno', 'Eficiência', 'Média de Acertos']].values.tolist()
164
+
165
+ return basic_stats
166
+
167
  def generate_graphs(self) -> List[plt.Figure]:
168
  """Gera gráficos para o relatório."""
169
  graphs = []
170
 
171
+ # 1. Distribuição de notas por nível
172
+ plt.figure(figsize=(12, 6))
173
+ nivel_counts = self.data['Nível'].value_counts()
174
+ colors = {'Avançado': 'green', 'Intermediário': 'yellow', 'Necessita Atenção': 'red'}
175
+ bars = plt.bar(nivel_counts.index, nivel_counts.values)
176
+ for i, bar in enumerate(bars):
177
+ bar.set_color(colors[nivel_counts.index[i]])
178
+ plt.text(bar.get_x() + bar.get_width()/2, bar.get_height(),
179
+ str(nivel_counts.values[i]),
180
+ ha='center', va='bottom')
181
+ plt.title('Distribuição dos Alunos por Nível de Desempenho')
182
  plt.ylabel('Número de Alunos')
 
183
  graphs.append(plt.gcf())
184
  plt.close()
185
 
186
+ # 2. Top 10 alunos
187
+ plt.figure(figsize=(12, 6))
188
+ top_10 = self.data.head(10)
189
+ acertos = top_10['Média de Acertos'].str.rstrip('%').astype(float)
190
+ plt.barh(top_10['Nome do Aluno'], acertos)
191
+ plt.title('Top 10 Alunos por Desempenho')
192
+ plt.xlabel('Percentual de Acertos')
193
+ for i, v in enumerate(acertos):
194
+ plt.text(v, i, f'{v:.1f}%', va='center')
195
+ plt.tight_layout()
196
+ graphs.append(plt.gcf())
197
+ plt.close()
198
+
199
+ # 3. Relação tempo x desempenho com níveis
200
  plt.figure(figsize=(10, 6))
201
+ colors = {'Avançado': 'green', 'Intermediário': 'yellow', 'Necessita Atenção': 'red'}
202
+ for nivel in colors:
203
+ mask = self.data['Nível'] == nivel
204
+ tempo = pd.to_timedelta(self.data[mask]['Total Tempo']).dt.total_seconds() / 60
205
+ acertos = self.data[mask]['Média de Acertos'].str.rstrip('%').astype(float)
206
+ plt.scatter(tempo, acertos, c=colors[nivel], label=nivel, alpha=0.6)
207
+ plt.title('Relação Tempo x Desempenho por Nível')
208
  plt.xlabel('Tempo Total (minutos)')
209
  plt.ylabel('Percentual de Acertos')
210
+ plt.legend()
211
+ plt.grid(True, alpha=0.3)
212
  graphs.append(plt.gcf())
213
  plt.close()
214
 
215
  return graphs
216
 
217
  def generate_pdf(self, output_path: str, graphs: List[plt.Figure]) -> None:
218
+ """Gera relatório em PDF com análise detalhada."""
219
  class PDF(FPDF):
220
  def header(self):
221
  self.set_font('Arial', 'B', 15)
 
231
  pdf.set_font('Arial', '', 10)
232
 
233
  summary_text = f"""
234
+ Visão Geral da Turma:
235
  - Média de Acertos: {self.stats['media_acertos']:.1f}%
236
  - Desvio Padrão: {self.stats['desvio_padrao']:.1f}%
237
  - Mediana: {self.stats['mediana_acertos']:.1f}%
238
+ - Total de Alunos: {self.stats['total_alunos']}
239
+
240
+ Destaques:
241
+ Top 3 Melhores Desempenhos:
242
  """
243
  pdf.multi_cell(0, 10, summary_text)
244
 
245
+ # Adicionar top performers
246
+ for aluno, nota in self.stats['top_performers']:
247
+ pdf.cell(0, 10, f"- {aluno}: {nota}", 0, 1)
248
+
249
+ pdf.ln()
250
+ pdf.cell(0, 10, "Alunos Mais Eficientes:", 0, 1)
251
+ for aluno, eficiencia, nota in self.stats['most_efficient']:
252
+ pdf.cell(0, 10, f"- {aluno}: Eficiência {eficiencia:.1f} (Acertos: {nota})", 0, 1)
253
+
254
+ # Gráficos e análises
255
  for i, graph in enumerate(graphs):
256
  pdf.add_page()
257
  graph_path = f'temp_graph_{i}.png'
 
259
  pdf.image(graph_path, x=10, y=30, w=270)
260
  os.remove(graph_path)
261
 
262
+ # Tabela detalhada por nível
263
+ for nivel in ['Avançado', 'Intermediário', 'Necessita Atenção']:
264
+ alunos_nivel = self.data[self.data['Nível'] == nivel]
265
+ if not alunos_nivel.empty:
266
+ pdf.add_page()
267
+ pdf.set_font('Arial', 'B', 12)
268
+ pdf.cell(0, 10, f'Alunos - Nível {nivel}', 0, 1)
269
+
270
+ # Cabeçalhos
271
+ columns = ['Nome do Aluno', 'Média de Acertos', 'Tarefas', 'Tempo Total', 'Eficiência']
272
+ widths = [80, 30, 30, 30, 30]
273
+ pdf.set_font('Arial', 'B', 8)
274
+ for i, col in enumerate(columns):
275
+ pdf.cell(widths[i], 7, col, 1)
276
+ pdf.ln()
277
+
278
+ # Dados
279
+ pdf.set_font('Arial', '', 8)
280
+ for _, row in alunos_nivel.iterrows():
281
+ pdf.cell(widths[0], 6, str(row['Nome do Aluno'])[:40], 1)
282
+ pdf.cell(widths[1], 6, str(row['Média de Acertos']), 1)
283
+ pdf.cell(widths[2], 6, str(row['Tarefas Completadas']), 1)
284
+ pdf.cell(widths[3], 6, str(row['Total Tempo']), 1)
285
+ pdf.cell(widths[4], 6, str(row['Eficiência']), 1)
286
+ pdf.ln()
287
 
288
  pdf.output(output_path)
289