Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -1,11 +1,11 @@
|
|
1 |
import pandas as pd
|
|
|
2 |
import numpy as np
|
3 |
-
import
|
4 |
-
import plotly.graph_objects as go
|
5 |
-
import gradio as gr
|
6 |
from datetime import datetime
|
7 |
-
|
8 |
-
|
|
|
9 |
|
10 |
cities_data = {
|
11 |
'Abancay': {
|
@@ -1151,14 +1151,17 @@ cities_data = {
|
|
1151 |
}
|
1152 |
|
1153 |
|
1154 |
-
|
1155 |
-
|
|
|
|
|
1156 |
|
1157 |
COLORES = {
|
1158 |
'Total': '#2C3E50',
|
1159 |
'Hombres': '#3498DB',
|
1160 |
'Mujeres': '#E74C3C',
|
1161 |
-
'Brecha': '#8E44AD'
|
|
|
1162 |
}
|
1163 |
|
1164 |
def normalizar_nombres_ciudades(nombre):
|
@@ -1173,225 +1176,388 @@ def normalizar_nombres_ciudades(nombre):
|
|
1173 |
'Pura': 'Piura',
|
1174 |
'Posalipa': 'Pucallpa',
|
1175 |
'Tagapito': 'Talara',
|
1176 |
-
'Juliana': 'Juliaca'
|
1177 |
-
'Chimbote': 'Chimbote',
|
1178 |
-
'Arequipa': 'Arequipa',
|
1179 |
-
'Trujillo': 'Trujillo'
|
1180 |
}
|
1181 |
return correcciones.get(nombre, nombre)
|
1182 |
|
1183 |
-
def
|
1184 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1185 |
|
1186 |
-
def
|
1187 |
-
|
1188 |
-
|
1189 |
-
|
1190 |
-
|
1191 |
-
|
1192 |
-
|
1193 |
-
|
1194 |
-
|
1195 |
-
|
1196 |
-
|
1197 |
-
|
1198 |
-
|
1199 |
-
|
1200 |
-
|
1201 |
-
|
1202 |
-
|
1203 |
-
|
1204 |
-
|
1205 |
-
|
1206 |
-
|
1207 |
-
|
1208 |
-
|
1209 |
-
|
1210 |
-
|
1211 |
-
|
1212 |
-
|
1213 |
-
|
1214 |
-
|
1215 |
-
|
1216 |
-
|
1217 |
-
|
1218 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1219 |
return fig
|
1220 |
|
1221 |
-
def
|
1222 |
-
|
1223 |
-
|
1224 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1225 |
nombre = normalizar_nombres_ciudades(ciudad)
|
1226 |
-
df = pd.DataFrame(
|
1227 |
-
|
1228 |
-
|
1229 |
-
|
1230 |
-
|
1231 |
|
1232 |
-
|
|
|
|
|
|
|
|
|
|
|
1233 |
|
1234 |
-
|
1235 |
-
|
1236 |
-
|
1237 |
-
|
1238 |
-
|
1239 |
-
|
1240 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1241 |
|
1242 |
-
|
1243 |
-
|
1244 |
-
|
1245 |
-
|
1246 |
-
|
1247 |
-
|
1248 |
-
height=600
|
1249 |
-
)
|
1250 |
|
1251 |
-
|
1252 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1253 |
|
1254 |
-
|
1255 |
-
|
1256 |
-
|
1257 |
-
|
1258 |
-
|
1259 |
-
|
1260 |
-
|
1261 |
-
|
1262 |
-
|
1263 |
-
|
|
|
|
|
1264 |
|
1265 |
-
|
1266 |
-
|
1267 |
-
|
1268 |
-
|
1269 |
-
|
1270 |
-
|
1271 |
-
name='Indicadores'
|
1272 |
-
))
|
1273 |
|
1274 |
-
|
1275 |
-
|
1276 |
-
|
1277 |
-
|
1278 |
-
|
1279 |
-
|
1280 |
-
|
1281 |
-
|
1282 |
-
|
1283 |
-
|
1284 |
-
|
1285 |
-
|
1286 |
-
|
1287 |
-
|
1288 |
-
|
1289 |
-
|
1290 |
-
|
1291 |
-
|
1292 |
-
|
1293 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1294 |
|
1295 |
-
def generar_analisis_global():
|
1296 |
figs = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1297 |
|
1298 |
-
|
1299 |
-
|
1300 |
-
|
1301 |
-
|
1302 |
-
datos_ingresos = []
|
1303 |
-
for ciudad, data in cities_data.items():
|
1304 |
-
nombre = normalizar_nombres_ciudades(ciudad)
|
1305 |
-
df = pd.DataFrame(data['ingresos_periodo'],
|
1306 |
-
columns=["Periodo", "Total", "Hombres", "Mujeres"])
|
1307 |
-
df['Ciudad'] = nombre
|
1308 |
-
datos_ingresos.append(df)
|
1309 |
-
|
1310 |
-
df_ingresos = pd.concat(datos_ingresos)
|
1311 |
-
fig_ingresos = px.line(df_ingresos,
|
1312 |
-
x='Periodo',
|
1313 |
-
y='Total',
|
1314 |
-
color='Ciudad',
|
1315 |
-
title='Evoluci贸n de Ingresos por Ciudad',
|
1316 |
-
markers=True)
|
1317 |
-
fig_ingresos.update_layout(height=600)
|
1318 |
-
figs.append(fig_ingresos)
|
1319 |
-
|
1320 |
-
# Gr谩fico de brecha salarial
|
1321 |
-
datos_brecha = []
|
1322 |
-
for ciudad, data in cities_data.items():
|
1323 |
-
nombre = normalizar_nombres_ciudades(ciudad)
|
1324 |
-
df = pd.DataFrame(data['ingresos_periodo'],
|
1325 |
-
columns=["Periodo", "Total", "Hombres", "Mujeres"])
|
1326 |
-
df['Brecha'] = (df['Hombres'] - df['Mujeres']) / df['Hombres'] * 100
|
1327 |
-
df['Ciudad'] = nombre
|
1328 |
-
datos_brecha.append(df)
|
1329 |
|
1330 |
-
|
1331 |
-
|
1332 |
-
|
1333 |
-
|
1334 |
-
|
1335 |
-
|
1336 |
-
|
1337 |
-
|
1338 |
-
|
|
|
1339 |
figs.append(fig_brecha)
|
1340 |
-
|
1341 |
return figs
|
1342 |
|
1343 |
-
with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue"), css=".gradio-container {background-color:
|
1344 |
-
gr.Markdown("# 馃搳 Dashboard
|
1345 |
-
|
|
|
1346 |
with gr.Row():
|
1347 |
-
|
1348 |
list(cities_data.keys()),
|
1349 |
-
label="
|
1350 |
value="Chimbote",
|
1351 |
-
|
1352 |
)
|
1353 |
-
|
1354 |
-
with gr.Tab("
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1355 |
with gr.Row():
|
1356 |
-
|
1357 |
-
ingresos_plot = gr.Plotly(label="Ingresos Promedio")
|
1358 |
with gr.Row():
|
1359 |
-
|
1360 |
-
actividad_plot = gr.Plotly(label="Tasa de Actividad")
|
1361 |
with gr.Row():
|
1362 |
-
|
1363 |
-
|
1364 |
-
|
1365 |
-
with gr.Tab("An谩lisis Comparativo"):
|
1366 |
with gr.Row():
|
1367 |
-
|
|
|
1368 |
with gr.Row():
|
1369 |
-
|
1370 |
-
|
1371 |
-
|
1372 |
-
|
1373 |
-
|
1374 |
-
|
1375 |
-
|
1376 |
-
|
1377 |
-
|
1378 |
-
|
1379 |
-
|
1380 |
-
|
1381 |
-
|
1382 |
-
|
1383 |
-
|
1384 |
-
|
1385 |
-
|
1386 |
-
|
1387 |
-
|
1388 |
-
|
1389 |
-
|
1390 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1391 |
]
|
1392 |
-
|
1393 |
-
|
1394 |
-
|
1395 |
-
|
|
|
|
|
|
|
1396 |
|
1397 |
app.launch(debug=True)
|
|
|
1 |
import pandas as pd
|
2 |
+
import matplotlib.pyplot as plt
|
3 |
import numpy as np
|
4 |
+
import matplotlib.dates as mdates
|
|
|
|
|
5 |
from datetime import datetime
|
6 |
+
import seaborn as sns
|
7 |
+
import gradio as gr
|
8 |
+
from matplotlib.figure import Figure
|
9 |
|
10 |
cities_data = {
|
11 |
'Abancay': {
|
|
|
1151 |
}
|
1152 |
|
1153 |
|
1154 |
+
plt.rcParams['figure.figsize'] = (14, 9)
|
1155 |
+
plt.rcParams['font.size'] = 13
|
1156 |
+
plt.rcParams['font.family'] = 'sans-serif'
|
1157 |
+
plt.style.use('seaborn-v0_8-whitegrid')
|
1158 |
|
1159 |
COLORES = {
|
1160 |
'Total': '#2C3E50',
|
1161 |
'Hombres': '#3498DB',
|
1162 |
'Mujeres': '#E74C3C',
|
1163 |
+
'Brecha': '#8E44AD',
|
1164 |
+
'Fondo': '#F8F9F9'
|
1165 |
}
|
1166 |
|
1167 |
def normalizar_nombres_ciudades(nombre):
|
|
|
1176 |
'Pura': 'Piura',
|
1177 |
'Posalipa': 'Pucallpa',
|
1178 |
'Tagapito': 'Talara',
|
1179 |
+
'Juliana': 'Juliaca'
|
|
|
|
|
|
|
1180 |
}
|
1181 |
return correcciones.get(nombre, nombre)
|
1182 |
|
1183 |
+
def ordenar_trimestres(df, col_fecha='Trimestre'):
|
1184 |
+
df = df.copy()
|
1185 |
+
if col_fecha == 'Trimestre':
|
1186 |
+
fechas = []
|
1187 |
+
for t in df[col_fecha]:
|
1188 |
+
if 'Q' in t:
|
1189 |
+
a帽o = t.split('-')[0]
|
1190 |
+
trimestre = t.split('-')[1]
|
1191 |
+
mes = {'Q1': '03', 'Q2': '06', 'Q3': '09', 'Q4': '12'}[trimestre]
|
1192 |
+
fechas.append(f"{a帽o}-{mes}")
|
1193 |
+
else:
|
1194 |
+
fechas.append(f"{t}-01")
|
1195 |
+
df['fecha_orden'] = pd.to_datetime(fechas, format='%Y-%m')
|
1196 |
+
else:
|
1197 |
+
fechas = []
|
1198 |
+
for p in df[col_fecha]:
|
1199 |
+
if '/' in p:
|
1200 |
+
fechas.append(p.split('/')[0])
|
1201 |
+
else:
|
1202 |
+
fechas.append(f"{p}-01")
|
1203 |
+
df['fecha_orden'] = pd.to_datetime(fechas, format='%Y-%m', errors='coerce')
|
1204 |
+
df = df.sort_values('fecha_orden')
|
1205 |
+
return df
|
1206 |
|
1207 |
+
def calcular_rango_y(df, categorias, padding=0.15):
|
1208 |
+
valores = df[categorias].values.flatten()
|
1209 |
+
valores = valores[~np.isnan(valores)]
|
1210 |
+
if len(valores) == 0:
|
1211 |
+
return (0, 1)
|
1212 |
+
min_val = np.nanmin(valores)
|
1213 |
+
max_val = np.nanmax(valores)
|
1214 |
+
rango = max_val - min_val
|
1215 |
+
return (max(0, min_val - rango*padding), max_val + rango*padding)
|
1216 |
+
|
1217 |
+
def graficar_datos_mejorados(df, titulo, subtitulo, ylabel, col_fecha='Trimestre', mostrar_valores=True, formato_valores='.1f'):
|
1218 |
+
fig, ax = plt.subplots(figsize=(14, 8))
|
1219 |
+
ax.set_facecolor(COLORES['Fondo'])
|
1220 |
+
fig.patch.set_facecolor(COLORES['Fondo'])
|
1221 |
+
ax.grid(axis='y', linestyle='--', alpha=0.7)
|
1222 |
+
|
1223 |
+
categorias = df.columns[1:4]
|
1224 |
+
x_indices = np.arange(len(df))
|
1225 |
+
ylim = calcular_rango_y(df, categorias)
|
1226 |
+
|
1227 |
+
for categoria in categorias:
|
1228 |
+
if categoria in df.columns and not df[categoria].isna().all():
|
1229 |
+
y_vals = df[categoria].values
|
1230 |
+
valid_mask = ~np.isnan(y_vals)
|
1231 |
+
|
1232 |
+
ax.plot(x_indices[valid_mask], y_vals[valid_mask],
|
1233 |
+
marker='o', linewidth=3, markersize=8,
|
1234 |
+
label=categoria, color=COLORES[categoria])
|
1235 |
+
|
1236 |
+
if mostrar_valores:
|
1237 |
+
for i, valor in zip(x_indices[valid_mask], y_vals[valid_mask]):
|
1238 |
+
offset = 0.2 if categoria == 'Hombres' else -0.8 if categoria == 'Mujeres' else 0
|
1239 |
+
ax.annotate(f'{valor:{formato_valores}}',
|
1240 |
+
xy=(i, valor),
|
1241 |
+
xytext=(0, 5 + offset),
|
1242 |
+
textcoords='offset points',
|
1243 |
+
ha='center', va='bottom',
|
1244 |
+
fontsize=10, fontweight='bold',
|
1245 |
+
color=COLORES[categoria],
|
1246 |
+
bbox=dict(boxstyle='round,pad=0.3', fc='white', alpha=0.7))
|
1247 |
+
|
1248 |
+
ax.set_title(titulo, fontsize=18, fontweight='bold', pad=20)
|
1249 |
+
plt.figtext(0.5, 0.01, subtitulo, ha='center', fontsize=12, fontstyle='italic')
|
1250 |
+
ax.set_ylabel(ylabel, fontsize=14, fontweight='bold')
|
1251 |
+
ax.set_xticks(x_indices)
|
1252 |
+
ax.set_xticklabels(df[col_fecha].astype(str), rotation=45, ha='right')
|
1253 |
+
ax.set_ylim(ylim)
|
1254 |
+
|
1255 |
+
for spine in ['top', 'right']:
|
1256 |
+
ax.spines[spine].set_visible(False)
|
1257 |
+
|
1258 |
+
legend = ax.legend(fontsize=12, frameon=True, framealpha=0.9,
|
1259 |
+
facecolor='white', edgecolor='lightgrey',
|
1260 |
+
loc='upper right', bbox_to_anchor=(0.98, 0.98))
|
1261 |
+
plt.tight_layout(rect=[0, 0.03, 1, 1])
|
1262 |
return fig
|
1263 |
|
1264 |
+
def generar_analisis_global():
|
1265 |
+
figuras = []
|
1266 |
+
estilo_comun = {
|
1267 |
+
'marker': 'o',
|
1268 |
+
'linewidth': 2,
|
1269 |
+
'markersize': 6,
|
1270 |
+
'alpha': 0.8
|
1271 |
+
}
|
1272 |
+
|
1273 |
+
# Gr谩fico de Desempleo Global
|
1274 |
+
fig_desempleo = Figure(figsize=(16, 10))
|
1275 |
+
ax_desempleo = fig_desempleo.add_subplot(111)
|
1276 |
+
for ciudad, datos in cities_data.items():
|
1277 |
nombre = normalizar_nombres_ciudades(ciudad)
|
1278 |
+
df = ordenar_trimestres(pd.DataFrame(datos['desempleo_trimestral'],
|
1279 |
+
columns=["Trimestre", "Total", "Hombres", "Mujeres"]))
|
1280 |
+
if not df.empty:
|
1281 |
+
ax_desempleo.plot(df['fecha_orden'], df['Total'],
|
1282 |
+
label=nombre, **estilo_comun)
|
1283 |
|
1284 |
+
ax_desempleo.set_title('TASA DE DESEMPLEO - COMPARATIVA ENTRE CIUDADES',
|
1285 |
+
fontsize=18, fontweight='bold', pad=20)
|
1286 |
+
ax_desempleo.set_ylabel('Tasa (%)', fontsize=14)
|
1287 |
+
ax_desempleo.grid(True, linestyle='--', alpha=0.5)
|
1288 |
+
ax_desempleo.xaxis.set_major_locator(mdates.YearLocator())
|
1289 |
+
ax_desempleo.xaxis.set_major_formatter(mdates.DateFormatter('%Y'))
|
1290 |
|
1291 |
+
handles, labels = ax_desempleo.get_legend_handles_labels()
|
1292 |
+
leg = fig_desempleo.legend(handles, labels,
|
1293 |
+
loc='upper center',
|
1294 |
+
bbox_to_anchor=(0.5, -0.12),
|
1295 |
+
ncol=5,
|
1296 |
+
fontsize=10,
|
1297 |
+
frameon=True,
|
1298 |
+
fancybox=True,
|
1299 |
+
shadow=True,
|
1300 |
+
title='Ciudades',
|
1301 |
+
title_fontsize='12')
|
1302 |
+
fig_desempleo.tight_layout(rect=[0, 0.1, 1, 0.95])
|
1303 |
+
figuras.append(fig_desempleo)
|
1304 |
+
|
1305 |
+
# Gr谩fico de Ingresos Global
|
1306 |
+
fig_ingresos = Figure(figsize=(16, 10))
|
1307 |
+
ax_ingresos = fig_ingresos.add_subplot(111)
|
1308 |
+
for ciudad, datos in cities_data.items():
|
1309 |
+
nombre = normalizar_nombres_ciudades(ciudad)
|
1310 |
+
df = ordenar_trimestres(pd.DataFrame(datos['ingresos_periodo'],
|
1311 |
+
columns=["Periodo", "Total", "Hombres", "Mujeres"]),
|
1312 |
+
'Periodo')
|
1313 |
+
if not df.empty:
|
1314 |
+
ax_ingresos.plot(df['fecha_orden'], df['Total'],
|
1315 |
+
label=nombre, **estilo_comun)
|
1316 |
|
1317 |
+
ax_ingresos.set_title('INGRESOS PROMEDIO - COMPARATIVA ENTRE CIUDADES',
|
1318 |
+
fontsize=18, fontweight='bold', pad=20)
|
1319 |
+
ax_ingresos.set_ylabel('Ingresos (Soles)', fontsize=14)
|
1320 |
+
ax_ingresos.grid(True, linestyle='--', alpha=0.5)
|
1321 |
+
ax_ingresos.xaxis.set_major_locator(mdates.YearLocator())
|
1322 |
+
ax_ingresos.xaxis.set_major_formatter(mdates.DateFormatter('%Y'))
|
|
|
|
|
1323 |
|
1324 |
+
handles, labels = ax_ingresos.get_legend_handles_labels()
|
1325 |
+
leg = fig_ingresos.legend(handles, labels,
|
1326 |
+
loc='upper center',
|
1327 |
+
bbox_to_anchor=(0.5, -0.12),
|
1328 |
+
ncol=5,
|
1329 |
+
fontsize=10,
|
1330 |
+
frameon=True,
|
1331 |
+
fancybox=True,
|
1332 |
+
shadow=True,
|
1333 |
+
title='Ciudades',
|
1334 |
+
title_fontsize='12')
|
1335 |
+
fig_ingresos.tight_layout(rect=[0, 0.1, 1, 0.95])
|
1336 |
+
figuras.append(fig_ingresos)
|
1337 |
|
1338 |
+
# Gr谩fico de Brecha Salarial Global
|
1339 |
+
fig_brecha = Figure(figsize=(16, 10))
|
1340 |
+
ax_brecha = fig_brecha.add_subplot(111)
|
1341 |
+
for ciudad, datos in cities_data.items():
|
1342 |
+
nombre = normalizar_nombres_ciudades(ciudad)
|
1343 |
+
df = ordenar_trimestres(pd.DataFrame(datos['ingresos_periodo'],
|
1344 |
+
columns=["Periodo", "Total", "Hombres", "Mujeres"]),
|
1345 |
+
'Periodo')
|
1346 |
+
if not df.empty and 'Hombres' in df.columns and 'Mujeres' in df.columns:
|
1347 |
+
df['Brecha'] = (df['Hombres'] - df['Mujeres']) / df['Hombres'] * 100
|
1348 |
+
ax_brecha.plot(df['fecha_orden'], df['Brecha'],
|
1349 |
+
label=nombre, **estilo_comun)
|
1350 |
|
1351 |
+
ax_brecha.set_title('BRECHA SALARIAL DE G脡NERO - COMPARATIVA ENTRE CIUDADES',
|
1352 |
+
fontsize=18, fontweight='bold', pad=20)
|
1353 |
+
ax_brecha.set_ylabel('Brecha (%)', fontsize=14)
|
1354 |
+
ax_brecha.grid(True, linestyle='--', alpha=0.5)
|
1355 |
+
ax_brecha.xaxis.set_major_locator(mdates.YearLocator())
|
1356 |
+
ax_brecha.xaxis.set_major_formatter(mdates.DateFormatter('%Y'))
|
|
|
|
|
1357 |
|
1358 |
+
handles, labels = ax_brecha.get_legend_handles_labels()
|
1359 |
+
leg = fig_brecha.legend(handles, labels,
|
1360 |
+
loc='upper center',
|
1361 |
+
bbox_to_anchor=(0.5, -0.12),
|
1362 |
+
ncol=5,
|
1363 |
+
fontsize=10,
|
1364 |
+
frameon=True,
|
1365 |
+
fancybox=True,
|
1366 |
+
shadow=True,
|
1367 |
+
title='Ciudades',
|
1368 |
+
title_fontsize='12')
|
1369 |
+
fig_brecha.tight_layout(rect=[0, 0.1, 1, 0.95])
|
1370 |
+
figuras.append(fig_brecha)
|
1371 |
+
|
1372 |
+
return figuras
|
1373 |
+
|
1374 |
+
def load_data(city):
|
1375 |
+
data = cities_data[city]
|
1376 |
+
return [
|
1377 |
+
data['desempleo_trimestral'],
|
1378 |
+
data['ingresos_periodo'],
|
1379 |
+
data['informal_periodo'],
|
1380 |
+
data['actividad_trimestral'],
|
1381 |
+
data['poblacion_ocupada']
|
1382 |
+
]
|
1383 |
+
|
1384 |
+
def generate_plots(desempleo_df, ingresos_df, informal_df, actividad_df, poblacion_df):
|
1385 |
+
dfs = {
|
1386 |
+
'desempleo': pd.DataFrame(desempleo_df, columns=["Trimestre", "Total", "Hombres", "Mujeres"]),
|
1387 |
+
'ingresos': pd.DataFrame(ingresos_df, columns=["Periodo", "Total", "Hombres", "Mujeres"]),
|
1388 |
+
'informal': pd.DataFrame(informal_df, columns=["Periodo", "Total", "Hombres", "Mujeres"]),
|
1389 |
+
'actividad': pd.DataFrame(actividad_df, columns=["Trimestre", "Total", "Hombres", "Mujeres"]),
|
1390 |
+
'poblacion': pd.DataFrame(poblacion_df, columns=["Trimestre", "Total", "Hombres", "Mujeres"])
|
1391 |
+
}
|
1392 |
+
|
1393 |
+
for key in dfs:
|
1394 |
+
for col in ["Total", "Hombres", "Mujeres"]:
|
1395 |
+
dfs[key][col] = pd.to_numeric(dfs[key][col], errors='coerce')
|
1396 |
+
|
1397 |
+
for key in dfs:
|
1398 |
+
dfs[key] = ordenar_trimestres(dfs[key], 'Trimestre' if key in ['desempleo', 'actividad', 'poblacion'] else 'Periodo')
|
1399 |
|
|
|
1400 |
figs = []
|
1401 |
+
|
1402 |
+
# Radar Plot
|
1403 |
+
problem_metrics = {
|
1404 |
+
'Desempleo': dfs['desempleo']['Total'].iloc[-1] if not dfs['desempleo'].empty else 0,
|
1405 |
+
'Informalidad': dfs['informal']['Total'].iloc[-1] if not dfs['informal'].empty else 0,
|
1406 |
+
'Brecha Salarial': (
|
1407 |
+
(dfs['ingresos']['Hombres'].iloc[-1] - dfs['ingresos']['Mujeres'].iloc[-1]) /
|
1408 |
+
dfs['ingresos']['Hombres'].iloc[-1] * 100
|
1409 |
+
if not dfs['ingresos'].empty and pd.notna(dfs['ingresos']['Hombres'].iloc[-1]) and pd.notna(dfs['ingresos']['Mujeres'].iloc[-1]) else 0
|
1410 |
+
),
|
1411 |
+
'Actividad': dfs['actividad']['Total'].iloc[-1] if not dfs['actividad'].empty else 0
|
1412 |
+
}
|
1413 |
+
|
1414 |
+
categories = list(problem_metrics.keys())
|
1415 |
+
values = list(problem_metrics.values())
|
1416 |
+
angles = np.linspace(0, 2*np.pi, len(categories), endpoint=False).tolist()
|
1417 |
+
values += values[:1]
|
1418 |
+
angles += angles[:1]
|
1419 |
+
|
1420 |
+
fig_radar, ax_radar = plt.subplots(figsize=(10, 10), subplot_kw=dict(polar=True))
|
1421 |
+
ax_radar.fill(angles, values, color=COLORES['Brecha'], alpha=0.2)
|
1422 |
+
ax_radar.set_theta_offset(np.pi/2)
|
1423 |
+
ax_radar.set_theta_direction(-1)
|
1424 |
+
ax_radar.set_thetagrids(np.degrees(angles[:-1]), labels=categories)
|
1425 |
+
ax_radar.set_rlabel_position(0)
|
1426 |
+
plt.yticks([20,40,60,80], ["20%","40%","60%","80%"], color="grey", size=10)
|
1427 |
+
plt.ylim(0,100)
|
1428 |
+
ax_radar.set_title(f'RADAR DE PROBLEM脕TICAS LABORALES\n{dfs["desempleo"]["Trimestre"].iloc[-1]}',
|
1429 |
+
pad=20, fontsize=14, fontweight='bold')
|
1430 |
+
figs.append(fig_radar)
|
1431 |
+
|
1432 |
+
# Gr谩ficos principales
|
1433 |
+
figs.append(graficar_datos_mejorados(dfs['desempleo'], 'TASA DE DESEMPLEO', 'Evoluci贸n por g茅nero', 'Tasa (%)'))
|
1434 |
+
figs.append(graficar_datos_mejorados(dfs['ingresos'], 'INGRESOS PROMEDIO', 'Por per铆odo y g茅nero', 'Ingreso (soles)', col_fecha='Periodo', formato_valores='.0f'))
|
1435 |
+
figs.append(graficar_datos_mejorados(dfs['informal'], 'TASA DE INFORMALIDAD', 'Por per铆odo', 'Tasa (%)', col_fecha='Periodo'))
|
1436 |
+
figs.append(graficar_datos_mejorados(dfs['actividad'], 'TASA DE ACTIVIDAD', 'Participaci贸n econ贸mica', 'Tasa (%)'))
|
1437 |
+
figs.append(graficar_datos_mejorados(dfs['poblacion'], 'POBLACI脫N OCUPADA', 'En miles de personas', 'Poblaci贸n (miles)'))
|
1438 |
+
|
1439 |
+
# Brecha Salarial
|
1440 |
+
ingresos = dfs['ingresos']
|
1441 |
+
brecha = []
|
1442 |
+
for h, m in zip(ingresos['Hombres'], ingresos['Mujeres']):
|
1443 |
+
if pd.notna(h) and pd.notna(m) and h != 0:
|
1444 |
+
brecha.append((h-m)/h*100)
|
1445 |
+
else:
|
1446 |
+
brecha.append(np.nan)
|
1447 |
|
1448 |
+
fig_brecha, ax_brecha = plt.subplots(figsize=(14,8))
|
1449 |
+
valid_indices = [i for i, b in enumerate(brecha) if pd.notna(b)]
|
1450 |
+
valid_periods = [str(ingresos['Periodo'].iloc[i]) for i in valid_indices]
|
1451 |
+
valid_brecha = [brecha[i] for i in valid_indices]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1452 |
|
1453 |
+
if valid_periods:
|
1454 |
+
bars = ax_brecha.bar(valid_periods, valid_brecha, color=COLORES['Brecha'])
|
1455 |
+
for bar in bars:
|
1456 |
+
height = bar.get_height()
|
1457 |
+
ax_brecha.text(bar.get_x() + bar.get_width()/2., height + 0.5,
|
1458 |
+
f'{height:.1f}%', ha='center', va='bottom',
|
1459 |
+
fontsize=10, fontweight='bold')
|
1460 |
+
ax_brecha.set_title('BRECHA SALARIAL DE G脡NERO', fontsize=18, pad=20)
|
1461 |
+
ax_brecha.set_ylabel('Brecha (%)', fontsize=14)
|
1462 |
+
ax_brecha.grid(axis='y', linestyle='--', alpha=0.7)
|
1463 |
figs.append(fig_brecha)
|
1464 |
+
|
1465 |
return figs
|
1466 |
|
1467 |
+
with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue"), css=".gradio-container {background-color: #F8F9F9}") as app:
|
1468 |
+
gr.Markdown("# 馃搳 Dashboard de Indicadores Laborales por G茅nero")
|
1469 |
+
gr.Markdown("Analiza los principales indicadores del mercado laboral con perspectiva de g茅nero")
|
1470 |
+
|
1471 |
with gr.Row():
|
1472 |
+
city = gr.Dropdown(
|
1473 |
list(cities_data.keys()),
|
1474 |
+
label="Seleccione una Ciudad",
|
1475 |
value="Chimbote",
|
1476 |
+
info="Elija la ciudad para visualizar sus datos"
|
1477 |
)
|
1478 |
+
|
1479 |
+
with gr.Tab("Datos"):
|
1480 |
+
with gr.Accordion("Tasa de Desempleo", open=True):
|
1481 |
+
desempleo_df = gr.Dataframe(
|
1482 |
+
headers=["Trimestre", "Total", "Hombres", "Mujeres"],
|
1483 |
+
datatype=["str", "number", "number", "number"],
|
1484 |
+
label="Datos de Desempleo"
|
1485 |
+
)
|
1486 |
+
with gr.Accordion("Ingresos", open=False):
|
1487 |
+
ingresos_df = gr.Dataframe(
|
1488 |
+
headers=["Periodo", "Total", "Hombres", "Mujeres"],
|
1489 |
+
datatype=["str", "number", "number", "number"],
|
1490 |
+
label="Datos de Ingresos"
|
1491 |
+
)
|
1492 |
+
with gr.Accordion("Informalidad", open=False):
|
1493 |
+
informal_df = gr.Dataframe(
|
1494 |
+
headers=["Periodo", "Total", "Hombres", "Mujeres"],
|
1495 |
+
datatype=["str", "number", "number", "number"],
|
1496 |
+
label="Datos de Informalidad"
|
1497 |
+
)
|
1498 |
+
with gr.Accordion("Actividad Econ贸mica", open=False):
|
1499 |
+
actividad_df = gr.Dataframe(
|
1500 |
+
headers=["Trimestre", "Total", "Hombres", "Mujeres"],
|
1501 |
+
datatype=["str", "number", "number", "number"],
|
1502 |
+
label="Datos de Actividad"
|
1503 |
+
)
|
1504 |
+
with gr.Accordion("Poblaci贸n Ocupada", open=False):
|
1505 |
+
poblacion_df = gr.Dataframe(
|
1506 |
+
headers=["Trimestre", "Total", "Hombres", "Mujeres"],
|
1507 |
+
datatype=["str", "number", "number", "number"],
|
1508 |
+
label="Datos de Poblaci贸n Ocupada"
|
1509 |
+
)
|
1510 |
+
|
1511 |
+
btn = gr.Button("Generar Visualizaciones", variant="primary")
|
1512 |
+
|
1513 |
+
with gr.Tab("Visualizaciones"):
|
1514 |
with gr.Row():
|
1515 |
+
radar_plot = gr.Plot(label="Radar de Problem谩ticas Laborales")
|
|
|
1516 |
with gr.Row():
|
1517 |
+
desempleo_plot = gr.Plot(label="Tasa de Desempleo")
|
|
|
1518 |
with gr.Row():
|
1519 |
+
ingresos_plot = gr.Plot(label="Ingresos Promedio")
|
1520 |
+
brecha_salarial_plot = gr.Plot(label="Brecha Salarial de G茅nero")
|
|
|
|
|
1521 |
with gr.Row():
|
1522 |
+
informalidad_plot = gr.Plot(label="Tasa de Informalidad")
|
1523 |
+
actividad_plot = gr.Plot(label="Tasa de Actividad")
|
1524 |
with gr.Row():
|
1525 |
+
poblacion_plot = gr.Plot(label="Poblaci贸n Ocupada")
|
1526 |
+
|
1527 |
+
with gr.Tab("An谩lisis Global"):
|
1528 |
+
gr.Markdown("## An谩lisis Comparativo entre Ciudades")
|
1529 |
+
global_btn = gr.Button("Generar An谩lisis Global", variant="primary")
|
1530 |
+
with gr.Row():
|
1531 |
+
global_desempleo_plot = gr.Plot(label="Comparativa de Desempleo")
|
1532 |
+
with gr.Row():
|
1533 |
+
global_ingresos_plot = gr.Plot(label="Comparativa de Ingresos")
|
1534 |
+
with gr.Row():
|
1535 |
+
global_brecha_plot = gr.Plot(label="Comparativa de Brecha Salarial")
|
1536 |
+
|
1537 |
+
city.change(
|
1538 |
+
fn=load_data,
|
1539 |
+
inputs=city,
|
1540 |
+
outputs=[desempleo_df, ingresos_df, informal_df, actividad_df, poblacion_df]
|
1541 |
+
)
|
1542 |
+
|
1543 |
+
btn.click(
|
1544 |
+
fn=generate_plots,
|
1545 |
+
inputs=[desempleo_df, ingresos_df, informal_df, actividad_df, poblacion_df],
|
1546 |
+
outputs=[
|
1547 |
+
radar_plot,
|
1548 |
+
desempleo_plot,
|
1549 |
+
ingresos_plot,
|
1550 |
+
informalidad_plot,
|
1551 |
+
actividad_plot,
|
1552 |
+
poblacion_plot,
|
1553 |
+
brecha_salarial_plot
|
1554 |
]
|
1555 |
+
)
|
1556 |
+
|
1557 |
+
global_btn.click(
|
1558 |
+
fn=generar_analisis_global,
|
1559 |
+
inputs=[],
|
1560 |
+
outputs=[global_desempleo_plot, global_ingresos_plot, global_brecha_plot]
|
1561 |
+
)
|
1562 |
|
1563 |
app.launch(debug=True)
|