Pikeras commited on
Commit
0f4ea72
verified
1 Parent(s): e761f51

Create visualizer.py

Browse files
Files changed (1) hide show
  1. src/modules/visualizer.py +263 -0
src/modules/visualizer.py ADDED
@@ -0,0 +1,263 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import matplotlib.pyplot as plt
2
+ import seaborn as sns
3
+ import plotly.express as px
4
+ import os
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ try:
9
+ from utils.reproducibility import set_seed
10
+ except ModuleNotFoundError:
11
+ sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
12
+ from utils.reproducibility import set_seed
13
+ # Establecer una semilla para reproducibilidad (descomenta para activar)
14
+ # set_seed(72)
15
+
16
+ # Clase encargada de la visualizaci贸n y guardado de los resultados y gr谩ficos del an谩lisis.
17
+ class Visualizer:
18
+ def __init__(self, config):
19
+ self.config = config
20
+
21
+ # Representaci贸n de resultados generales (vista r谩pida del rendimiento general)
22
+ def plot_resultados_generales(self, df_acumulado, carpeta_graficos):
23
+ resultados_filtrados = df_acumulado[df_acumulado['resultado'].isin(['acierto', 'error', 'fallo'])]
24
+ resultados_counts = resultados_filtrados['resultado'].value_counts()
25
+ plt.figure(figsize=(6, 4))
26
+ sns.barplot(x=resultados_counts.index, y=resultados_counts.values, palette='pastel')
27
+ plt.title('Distribuci贸n de Resultados Generales')
28
+ plt.ylabel('Cantidad de respuestas')
29
+ plt.xlabel('Resultado')
30
+ plt.tight_layout()
31
+ plt.savefig(os.path.join(carpeta_graficos, 'resultados_generales.png'))
32
+
33
+ # Distribuci贸n de aciertos/fallos/errores por tipo de evaluaci贸n
34
+ def plot_resultados_tipo_evaluacion(self, df_acumulado, carpeta_graficos):
35
+ df_filtrado = df_acumulado[df_acumulado['resultado'].isin(['acierto', 'error', 'fallo'])]
36
+ plt.figure(figsize=(12, 6))
37
+ sns.countplot(
38
+ data=df_filtrado,
39
+ x='tipo_evaluacion',
40
+ hue='resultado',
41
+ palette='Set2',
42
+ edgecolor='black'
43
+ )
44
+ plt.title('Distribuci贸n de Aciertos, Fallos y Errores por Tipo de Evaluaci贸n', fontsize=14)
45
+ plt.xlabel('Tipo de Evaluaci贸n')
46
+ plt.ylabel('Cantidad de Respuestas')
47
+ plt.legend(title='Resultado')
48
+ plt.xticks(rotation=70)
49
+ plt.tight_layout()
50
+ plt.savefig(os.path.join(carpeta_graficos, 'resultados_tipo_evaluacion.png'))
51
+
52
+ # Mapa de calor de proporciones por tipo de evaluaci贸n
53
+ def plot_mapa_calor(self, df_acumulado, carpeta_graficos):
54
+ df_mapa_calor = df_acumulado.groupby(['tipo_evaluacion', 'resultado']).size().unstack(fill_value=0)
55
+ df_mapa_calor_prop = df_mapa_calor.div(df_mapa_calor.sum(axis=1), axis=0)
56
+ plt.figure(figsize=(10, 6))
57
+ sns.heatmap(df_mapa_calor_prop, annot=True, fmt=".2f", cmap='YlGnBu', cbar_kws={'label': 'Proporci贸n'})
58
+ plt.title('Proporci贸n de Resultados por Tipo de Evaluaci贸n')
59
+ plt.xlabel('Resultado')
60
+ plt.ylabel('Tipo de Evaluaci贸n')
61
+ plt.tight_layout()
62
+ plt.savefig(os.path.join(carpeta_graficos, 'mapa_calor_tipo_evaluacion.png'))
63
+
64
+ # Mapa interactivo por comunidad sensible (histograma facetado)
65
+ def plot_interactive(self, df_acumulado, carpeta_graficos, abreviaciones):
66
+ df_acumulado['tipo_evaluacion'] = df_acumulado['tipo_evaluacion'].replace(abreviaciones)
67
+ df_acumulado['comunidad_sensible'] = df_acumulado['comunidad_sensible'].astype(str)
68
+ fig = px.histogram(
69
+ df_acumulado,
70
+ x="tipo_evaluacion",
71
+ color="resultado",
72
+ barmode="group",
73
+ facet_col="comunidad_sensible",
74
+ category_orders={"resultado": ["acierto", "fallo", "error"]},
75
+ title="Distribuci贸n por comunidad sensible"
76
+ )
77
+ for annotation in fig.layout.annotations:
78
+ if 'comunidad_sensible=' in annotation.text:
79
+ annotation.text = annotation.text.split('=')[1]
80
+ annotation.textangle = -15
81
+ if "tipo_evaluacion" in annotation.text:
82
+ annotation.text = ""
83
+ fig.update_layout(
84
+ xaxis_title="",
85
+ yaxis_title="Cantidad de respuestas",
86
+ legend_title="Resultado",
87
+ margin=dict(l=20, r=20, t=120, b=100),
88
+ height=600,
89
+ bargap=0.3
90
+ )
91
+ fig.update_xaxes(tickangle=-45)
92
+ fig.write_html(os.path.join(carpeta_graficos, 'grafico_resultados_interactivo.html'))
93
+
94
+ # Gr谩fico de z-scores y outliers para an谩lisis de sentimiento
95
+ def plot_outliers_analisis_sentimiento(self, df_acumulado, carpeta_graficos):
96
+ if 'z_outlier' not in df_acumulado.columns:
97
+ return
98
+ datos = df_acumulado[df_acumulado['tipo_evaluacion'] == 'preguntas_analisis_sentimiento']
99
+ if datos.empty:
100
+ return
101
+ datos = datos.dropna(subset=['z_neg', 'z_neu', 'z_pos', 'z_outlier'])
102
+ fig, axes = plt.subplots(2, 1, figsize=(14, 8), sharex=True, gridspec_kw={'height_ratios': [3, 1]})
103
+ plt.suptitle("Distribuci贸n de resultados - Preguntas An谩lisis Sentimiento", fontsize=16)
104
+ # Parte superior: l铆neas z_neg, z_neu, z_pos
105
+ axes[0].plot(datos.index, datos['z_neg'], label='z_neg', color='red')
106
+ axes[0].plot(datos.index, datos['z_neu'], label='z_neu', color='gray')
107
+ axes[0].plot(datos.index, datos['z_pos'], label='z_pos', color='green')
108
+ axes[0].axhline(2, color='black', linestyle='--', linewidth=1, label='umbral=2')
109
+ axes[0].legend()
110
+ axes[0].set_ylabel("Z-score")
111
+ axes[0].set_title("Z-scores por entrada")
112
+ sns.scatterplot(
113
+ x=datos.index,
114
+ y=['Outlier'] * len(datos),
115
+ hue=datos['z_outlier'],
116
+ palette={'positivo': 'green', 'negativo': 'red', 'neutral': 'gray', 'ninguno': 'blue'},
117
+ ax=axes[1],
118
+ s=60
119
+ )
120
+ for i, row in datos.iterrows():
121
+ if row['z_outlier'] != 'ninguno':
122
+ nombre = row['comunidad_sensible']
123
+ axes[1].annotate(
124
+ nombre,
125
+ (i, 0),
126
+ textcoords="offset points",
127
+ xytext=(0, -80),
128
+ ha='center',
129
+ fontsize=7,
130
+ rotation=90,
131
+ clip_on=False
132
+ )
133
+ axes[1].set_title("Clasificaci贸n de outliers an谩lisis sentimiento")
134
+ axes[1].legend(
135
+ title="Outlier",
136
+ bbox_to_anchor=(0.5, 1.25),
137
+ loc='lower center',
138
+ ncol=4,
139
+ frameon=True
140
+ )
141
+ axes[1].set_xticks([])
142
+ axes[1].set_xlabel("")
143
+ plt.tight_layout(rect=[0, 0.01, 1, 0.95])
144
+ plt.subplots_adjust(top=0.88)
145
+ plt.savefig(os.path.join(carpeta_graficos, 'outliers_analisis_sentimiento.png'))
146
+
147
+ # Gr谩fico de z-score y outliers para cerradas probabilidad
148
+ def plot_outliers_cerradas_probabilidad(self, df_acumulado, carpeta_graficos):
149
+ if 'z_outlier' not in df_acumulado.columns:
150
+ return
151
+ datos = df_acumulado[df_acumulado['tipo_evaluacion'] == 'preguntas_cerradas_probabilidad']
152
+ if datos.empty:
153
+ return
154
+ datos = datos.dropna(subset=['z_probabilidad', 'z_outlier'])
155
+ fig, axes = plt.subplots(2, 1, figsize=(14, 6), sharex=True, gridspec_kw={'height_ratios': [3, 1]})
156
+ plt.suptitle("Z-score y clasificaci贸n de outliers - Preguntas Cerradas Probabilidad", fontsize=16)
157
+ axes[0].plot(datos.index, datos['z_probabilidad'], color='purple', label='z_probabilidad')
158
+ axes[0].axhline(1.5, color='green', linestyle='--', label='umbral superior')
159
+ axes[0].axhline(-1.5, color='red', linestyle='--', label='umbral inferior')
160
+ axes[0].set_ylabel("Z-score")
161
+ axes[0].legend()
162
+ axes[0].set_title("Z-score de probabilidad por entrada")
163
+ # Parte inferior: z_outlier
164
+ sns.scatterplot(
165
+ x=datos.index,
166
+ y=['Outlier'] * len(datos),
167
+ hue=datos['z_outlier'],
168
+ palette={'superior': 'green', 'inferior': 'red', 'neutral': 'gray'},
169
+ ax=axes[1],
170
+ s=60
171
+ )
172
+ for i, row in datos.iterrows():
173
+ if row['z_outlier'] != 'neutral':
174
+ nombre = row['comunidad_sensible']
175
+ axes[1].annotate(
176
+ nombre,
177
+ (i, 0),
178
+ textcoords="offset points",
179
+ xytext=(0, -80),
180
+ ha='center',
181
+ fontsize=7,
182
+ rotation=90,
183
+ clip_on=False
184
+ )
185
+ axes[1].set_title("Clasificaci贸n de outliers cerradas probabilidad")
186
+ axes[1].legend(
187
+ title="Outlier",
188
+ bbox_to_anchor=(0.5, 1.25),
189
+ loc='lower center',
190
+ ncol=4,
191
+ frameon=True
192
+ )
193
+ axes[1].set_xticks([])
194
+ axes[1].set_xlabel("")
195
+ plt.tight_layout(rect=[0, 0.01, 1, 0.95])
196
+ plt.subplots_adjust(top=0.88)
197
+ plt.savefig(os.path.join(carpeta_graficos, 'outliers_cerradas_probabilidad.png'))
198
+
199
+ # Gr谩fico de balance, % fuera de contexto y outliers para respuestas m煤ltiples
200
+ def plot_outliers_respuestas_multiples(self, df_acumulado, carpeta_graficos):
201
+ if 'z_outlier' not in df_acumulado.columns:
202
+ return
203
+ datos = df_acumulado[df_acumulado['tipo_evaluacion'] == 'preguntas_respuestas_multiples']
204
+ if datos.empty:
205
+ return
206
+ datos = datos.dropna(subset=['balance_estereotipos', 'porcentaje_fuera_contexto', 'z_outlier'])
207
+ fig, axes = plt.subplots(3, 1, figsize=(14, 10), sharex=True, gridspec_kw={'height_ratios': [3, 3, 1]})
208
+ plt.suptitle("Distribuci贸n de resultados - Preguntas Respuestas M煤ltiples", fontsize=16)
209
+
210
+ axes[0].plot(datos.index, datos['balance_estereotipos'], label='Balance Estereotipos', color='blue')
211
+ axes[0].set_ylabel("Balance Estereotipos")
212
+ axes[0].set_title("Balance de estereotipos por entrada")
213
+ axes[0].legend()
214
+
215
+ axes[1].plot(datos.index, datos['porcentaje_fuera_contexto'], label='% Fuera de Contexto', color='orange')
216
+ axes[1].axhline(20, color='black', linestyle='--', linewidth=1, label='umbral=20%')
217
+ axes[1].set_ylabel("% Fuera de Contexto")
218
+ axes[1].set_ylim(0, 100)
219
+ axes[1].set_title("Porcentaje de respuestas fuera de contexto por entrada")
220
+ axes[1].legend()
221
+
222
+ sns.scatterplot(
223
+ x=datos.index,
224
+ y=['Outlier'] * len(datos),
225
+ hue=datos['z_outlier'],
226
+ palette={
227
+ 'antioestereotipada_y_fuera_de_contexto': 'purple',
228
+ 'estereotipada_y_fuera_de_contexto': 'brown',
229
+ 'antioestereotipada': 'green',
230
+ 'estereotipada': 'red',
231
+ 'fuera_de_contexto': 'black',
232
+ 'neutral': 'gray'
233
+ },
234
+ ax=axes[2],
235
+ s=70
236
+ )
237
+ for i, row in datos.iterrows():
238
+ if row['z_outlier'] != 'neutral':
239
+ nombre = row['comunidad_sensible']
240
+ axes[2].annotate(
241
+ nombre,
242
+ (i, 0),
243
+ textcoords="offset points",
244
+ xytext=(0, -80),
245
+ ha='center',
246
+ fontsize=7,
247
+ rotation=90,
248
+ clip_on=False
249
+ )
250
+ axes[2].set_yticks([])
251
+ axes[2].set_title("Clasificaci贸n de outliers")
252
+ axes[2].legend(
253
+ title="Outlier",
254
+ bbox_to_anchor=(0.5, 1.25),
255
+ loc='lower center',
256
+ ncol=2,
257
+ frameon=True
258
+ )
259
+ axes[2].set_xticks([])
260
+ axes[2].set_xlabel("")
261
+ plt.tight_layout(rect=[0, 0.05, 1, 0.95])
262
+ plt.subplots_adjust(top=0.88)
263
+ plt.savefig(os.path.join(carpeta_graficos, 'outliers_respuestas_multiples.png'))