C2MV commited on
Commit
11a1cbb
verified
1 Parent(s): cc01c98

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +111 -101
app.py CHANGED
@@ -1175,7 +1175,15 @@ def normalizar_nombres_ciudades(nombre):
1175
  'Juliana': 'Juliaca',
1176
  'Chimbote': 'Chimbote',
1177
  'Arequipa': 'Arequipa',
1178
- 'Trujillo': 'Trujillo'
 
 
 
 
 
 
 
 
1179
  }
1180
  return correcciones.get(nombre, nombre)
1181
 
@@ -1195,10 +1203,7 @@ def crear_grafico_lineas(df, titulo, eje_y, formato=None):
1195
  y=df[columna],
1196
  name=columna,
1197
  mode='lines+markers',
1198
- line=dict(
1199
- color=COLORES.get(columna, '#000000'),
1200
- width=3
1201
- ),
1202
  marker=dict(size=8),
1203
  hovertemplate=f'<b>{columna}</b>: %{{y:{formato or ".2f"}}}<extra></extra>'
1204
  ))
@@ -1209,13 +1214,7 @@ def crear_grafico_lineas(df, titulo, eje_y, formato=None):
1209
  xaxis_title='Periodo',
1210
  hovermode='x unified',
1211
  template='plotly_white',
1212
- legend=dict(
1213
- orientation="h",
1214
- yanchor="bottom",
1215
- y=1.02,
1216
- xanchor="right",
1217
- x=1
1218
- ),
1219
  height=500
1220
  )
1221
 
@@ -1224,53 +1223,81 @@ def crear_grafico_lineas(df, titulo, eje_y, formato=None):
1224
 
1225
  return fig
1226
 
1227
- def crear_radar_plot(dfs):
1228
- metricas = {}
1229
-
1230
- try:
1231
- metricas['Desempleo'] = dfs['desempleo']['Total'].iloc[-1]
1232
- metricas['Informalidad'] = dfs['informal']['Total'].iloc[-1]
1233
- metricas['Actividad'] = dfs['actividad']['Total'].iloc[-1]
1234
- metricas['Brecha Salarial'] = ((dfs['ingresos']['Hombres'].iloc[-1] -
1235
- dfs['ingresos']['Mujeres'].iloc[-1]) /
1236
- dfs['ingresos']['Hombres'].iloc[-1]) * 100
1237
- except (KeyError, IndexError, ZeroDivisionError) as e:
1238
- print(f"Error al generar radar plot: {str(e)}")
1239
- return go.Figure()
1240
 
1241
- categories = list(metricas.keys())
1242
- values = list(metricas.values())
 
1243
 
1244
- fig = go.Figure()
 
 
 
1245
 
1246
- fig.add_trace(go.Scatterpolar(
1247
- r=values + [values[0]],
1248
- theta=categories + [categories[0]],
1249
- fill='toself',
1250
- fillcolor='rgba(142, 68, 173, 0.2)',
1251
- line=dict(color=COLORES['Brecha'], width=2),
1252
- name='Indicadores'
1253
- ))
 
1254
 
1255
  fig.update_layout(
1256
- polar=dict(
1257
- radialaxis=dict(visible=True, range=[0, 100], tickfont=dict(size=12)),
1258
- angularaxis=dict(rotation=90, direction='clockwise', tickfont=dict(size=14))
1259
- ),
1260
- title=dict(text='Radar de Indicadores Laborales', x=0.5, font=dict(size=20)),
1261
- showlegend=False,
1262
- height=500
1263
  )
1264
 
 
1265
  return fig
1266
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1267
  def analisis_comparativo_desempleo():
1268
  datos = []
1269
-
1270
  for ciudad, data in cities_data.items():
1271
  nombre = normalizar_nombres_ciudades(ciudad)
1272
- df = procesar_dataframe(data['desempleo_trimestral'],
1273
- ["Trimestre", "Total", "Hombres", "Mujeres"])
1274
  if not df.empty:
1275
  ultimo_valor = df['Total'].iloc[-1]
1276
  datos.append({'Ciudad': nombre, 'Desempleo': ultimo_valor})
@@ -1279,66 +1306,57 @@ def analisis_comparativo_desempleo():
1279
  return go.Figure()
1280
 
1281
  df_comparativo = pd.DataFrame(datos).sort_values('Desempleo', ascending=False)
1282
-
1283
  fig = px.bar(df_comparativo,
1284
  x='Ciudad',
1285
  y='Desempleo',
1286
  color='Desempleo',
1287
  color_continuous_scale='Bluered',
1288
  text_auto='.1f%',
1289
- title='Comparaci贸n de Tasa de Desempleo entre Ciudades')
 
1290
 
1291
  fig.update_layout(
1292
  xaxis_title='',
1293
  yaxis_title='Tasa de Desempleo (%)',
1294
  coloraxis_showscale=False,
1295
  xaxis={'categoryorder':'total descending'},
1296
- height=600
1297
  )
1298
-
1299
  return fig
1300
 
1301
  def generar_analisis_global():
1302
  figs = []
1303
 
1304
- # Gr谩fico comparativo de desempleo
1305
  figs.append(analisis_comparativo_desempleo())
1306
 
1307
- # Gr谩fico de tendencia de ingresos (full width)
1308
  datos_ingresos = []
1309
  for ciudad, data in cities_data.items():
1310
  nombre = normalizar_nombres_ciudades(ciudad)
1311
- df = procesar_dataframe(data['ingresos_periodo'],
1312
- ["Periodo", "Total", "Hombres", "Mujeres"])
1313
  if not df.empty:
1314
  df['Ciudad'] = nombre
1315
  datos_ingresos.append(df)
1316
 
1317
  if datos_ingresos:
1318
  df_ingresos = pd.concat(datos_ingresos)
1319
- fig_ingresos = px.line(df_ingresos,
1320
- x='Periodo',
1321
- y='Total',
1322
- color='Ciudad',
1323
- title='<b>Evoluci贸n Hist贸rica de Ingresos Promedio por Ciudad</b>',
1324
- markers=True,
1325
- height=600)
1326
- fig_ingresos.update_layout(
1327
- xaxis_title='Periodo',
1328
- yaxis_title='Ingresos (Soles)',
1329
- legend=dict(title='Ciudades'),
1330
- margin=dict(l=50, r=50, t=80, b=50)
1331
  )
1332
  figs.append(fig_ingresos)
1333
  else:
1334
  figs.append(go.Figure())
1335
 
1336
- # Gr谩fico de brecha salarial (full width)
1337
  datos_brecha = []
1338
  for ciudad, data in cities_data.items():
1339
  nombre = normalizar_nombres_ciudades(ciudad)
1340
- df = procesar_dataframe(data['ingresos_periodo'],
1341
- ["Periodo", "Total", "Hombres", "Mujeres"])
1342
  if not df.empty:
1343
  df['Brecha'] = (df['Hombres'] - df['Mujeres']) / df['Hombres'].replace(0, np.nan) * 100
1344
  df['Ciudad'] = nombre
@@ -1346,23 +1364,12 @@ def generar_analisis_global():
1346
 
1347
  if datos_brecha:
1348
  df_brecha = pd.concat(datos_brecha)
1349
- fig_brecha = px.bar(df_brecha,
1350
- x='Ciudad',
1351
- y='Brecha',
1352
- color='Brecha',
1353
- title='<b>Comparaci贸n de Brecha Salarial por Ciudad</b>',
1354
- text_auto='.1f%',
1355
- height=600,
1356
- color_continuous_scale='Viridis')
1357
-
1358
- fig_brecha.update_layout(
1359
- xaxis_title='Ciudad',
1360
- yaxis_title='Brecha Salarial (%)',
1361
- coloraxis_showscale=False,
1362
- xaxis={'categoryorder':'total descending'},
1363
- margin=dict(l=50, r=50, t=80, b=150),
1364
- uniformtext_minsize=8,
1365
- uniformtext_mode='hide'
1366
  )
1367
  figs.append(fig_brecha)
1368
  else:
@@ -1394,6 +1401,7 @@ def actualizar_graficos(ciudad):
1394
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue"), css="""
1395
  .gradio-container {background-color: #f8f9fa}
1396
  .plot-container {margin: 20px 0}
 
1397
  """) as app:
1398
 
1399
  gr.Markdown("# 馃搳 Dashboard Anal铆tico del Mercado Laboral Peruano")
@@ -1407,34 +1415,36 @@ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue"), css="""
1407
  )
1408
 
1409
  with gr.Tab("An谩lisis por Ciudad"):
 
1410
  with gr.Row():
1411
- desempleo_plot = Plot(label="Tasa de Desempleo")
1412
- with gr.Row():
1413
- ingresos_plot = Plot(label="Ingresos Promedio")
1414
- with gr.Row():
1415
- informalidad_plot = Plot(label="Tasa de Informalidad")
1416
- with gr.Row():
1417
- actividad_plot = Plot(label="Tasa de Actividad")
1418
- with gr.Row():
1419
- radar_plot = Plot(label="Radar de Indicadores")
1420
  with gr.Row():
1421
- brecha_plot = Plot(label="Brecha Salarial")
 
 
 
 
 
 
 
1422
 
1423
  with gr.Tab("An谩lisis Comparativo"):
1424
  with gr.Row():
1425
  global_desempleo = Plot(label="Ranking de Desempleo")
1426
  with gr.Row():
1427
- global_ingresos = Plot(label="Evoluci贸n de Ingresos")
1428
  with gr.Row():
1429
- global_brecha = Plot(label="Comparaci贸n de Brecha Salarial")
1430
  with gr.Row():
1431
- global_btn = gr.Button("Actualizar Datos", variant="primary")
1432
 
1433
- # Eventos
1434
  ciudad.change(
1435
  fn=actualizar_graficos,
1436
  inputs=ciudad,
1437
- outputs=[desempleo_plot, ingresos_plot, informalidad_plot, actividad_plot, radar_plot, brecha_plot]
1438
  )
1439
 
1440
  global_btn.click(
 
1175
  'Juliana': 'Juliaca',
1176
  'Chimbote': 'Chimbote',
1177
  'Arequipa': 'Arequipa',
1178
+ 'Trujillo': 'Trujillo',
1179
+ 'Cervo de Pasco': 'Cerro de Pasco',
1180
+ 'Lima Metropolitana y la Provincia Constitucional del Calleo': 'Lima-Callao',
1181
+ 'Moyaegua': 'Moquegua',
1182
+ 'Mayobamba': 'Moyobamba',
1183
+ 'Hueva': 'Huancavelica',
1184
+ 'Pluto J煤nior': 'Piura',
1185
+ 'Guido Mianzano': 'Cajamarca',
1186
+ 'Guyo Morales': 'Ayacucho'
1187
  }
1188
  return correcciones.get(nombre, nombre)
1189
 
 
1203
  y=df[columna],
1204
  name=columna,
1205
  mode='lines+markers',
1206
+ line=dict(color=COLORES.get(columna, '#000000'), width=3),
 
 
 
1207
  marker=dict(size=8),
1208
  hovertemplate=f'<b>{columna}</b>: %{{y:{formato or ".2f"}}}<extra></extra>'
1209
  ))
 
1214
  xaxis_title='Periodo',
1215
  hovermode='x unified',
1216
  template='plotly_white',
1217
+ legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1),
 
 
 
 
 
 
1218
  height=500
1219
  )
1220
 
 
1223
 
1224
  return fig
1225
 
1226
+ def crear_grafico_barras_anual(df, titulo, eje_y, columna_metricas, palette=px.colors.sequential.Viridis):
1227
+ # Ordenar datos de mayor a menor
1228
+ df = df.sort_values(by=columna_metricas, ascending=False)
 
 
 
 
 
 
 
 
 
 
1229
 
1230
+ # Resto de la funci贸n se mantiene igual
1231
+ df['A帽o'] = df['Periodo'].str.split('-').str[0]
1232
+ df = df.groupby(['Ciudad', 'A帽o'], as_index=False)[columna_metricas].mean()
1233
 
1234
+ # Crear categor铆as ordenadas
1235
+ orden_ciudades = df.groupby('Ciudad')[columna_metricas].mean().sort_values(ascending=False).index
1236
+ df['Ciudad'] = pd.Categorical(df['Ciudad'], categories=orden_ciudades, ordered=True)
1237
+ df = df.sort_values('Ciudad')
1238
 
1239
+ fig = px.bar(df,
1240
+ x='Ciudad',
1241
+ y=columna_metricas,
1242
+ color='A帽o',
1243
+ barmode='group',
1244
+ title=f'<b>{titulo}</b>',
1245
+ labels={columna_metricas: eje_y},
1246
+ color_discrete_sequence=palette,
1247
+ height=600)
1248
 
1249
  fig.update_layout(
1250
+ xaxis_title='Ciudad',
1251
+ yaxis_title=eje_y,
1252
+ legend_title='A帽o',
1253
+ xaxis={'categoryorder': 'total descending'},
1254
+ uniformtext_minsize=8,
1255
+ margin=dict(b=150),
1256
+ hovermode='x unified'
1257
  )
1258
 
1259
+ fig.update_xaxes(tickangle=45)
1260
  return fig
1261
 
1262
+ def crear_radar_plot(dfs):
1263
+ try:
1264
+ metricas = {
1265
+ 'Desempleo': dfs['desempleo']['Total'].iloc[-1],
1266
+ 'Informalidad': dfs['informal']['Total'].iloc[-1],
1267
+ 'Actividad': dfs['actividad']['Total'].iloc[-1],
1268
+ 'Brecha Salarial': ((dfs['ingresos']['Hombres'].iloc[-1] - dfs['ingresos']['Mujeres'].iloc[-1]) /
1269
+ dfs['ingresos']['Hombres'].iloc[-1]) * 100
1270
+ }
1271
+
1272
+ fig = go.Figure()
1273
+ fig.add_trace(go.Scatterpolar(
1274
+ r=list(metricas.values()) + [list(metricas.values())[0]],
1275
+ theta=list(metricas.keys()) + [list(metricas.keys())[0]],
1276
+ fill='toself',
1277
+ fillcolor='rgba(142, 68, 173, 0.2)',
1278
+ line=dict(color=COLORES['Brecha'], width=2)
1279
+ ))
1280
+
1281
+ fig.update_layout(
1282
+ polar=dict(
1283
+ radialaxis=dict(visible=True, range=[0, 100]),
1284
+ angularaxis=dict(rotation=90, direction='clockwise')
1285
+ ),
1286
+ title=dict(text='Radar de Indicadores Laborales', x=0.5, font=dict(size=20)),
1287
+ showlegend=False,
1288
+ height=500
1289
+ )
1290
+ return fig
1291
+
1292
+ except Exception as e:
1293
+ print(f"Error en radar plot: {str(e)}")
1294
+ return go.Figure()
1295
+
1296
  def analisis_comparativo_desempleo():
1297
  datos = []
 
1298
  for ciudad, data in cities_data.items():
1299
  nombre = normalizar_nombres_ciudades(ciudad)
1300
+ df = procesar_dataframe(data['desempleo_trimestral'], ["Trimestre", "Total", "Hombres", "Mujeres"])
 
1301
  if not df.empty:
1302
  ultimo_valor = df['Total'].iloc[-1]
1303
  datos.append({'Ciudad': nombre, 'Desempleo': ultimo_valor})
 
1306
  return go.Figure()
1307
 
1308
  df_comparativo = pd.DataFrame(datos).sort_values('Desempleo', ascending=False)
 
1309
  fig = px.bar(df_comparativo,
1310
  x='Ciudad',
1311
  y='Desempleo',
1312
  color='Desempleo',
1313
  color_continuous_scale='Bluered',
1314
  text_auto='.1f%',
1315
+ title='<b>Comparaci贸n de Tasa de Desempleo entre Ciudades</b>',
1316
+ height=600)
1317
 
1318
  fig.update_layout(
1319
  xaxis_title='',
1320
  yaxis_title='Tasa de Desempleo (%)',
1321
  coloraxis_showscale=False,
1322
  xaxis={'categoryorder':'total descending'},
1323
+ margin=dict(b=150)
1324
  )
 
1325
  return fig
1326
 
1327
  def generar_analisis_global():
1328
  figs = []
1329
 
1330
+ # 1. Ranking de Desempleo
1331
  figs.append(analisis_comparativo_desempleo())
1332
 
1333
+ # 2. Evoluci贸n de Ingresos
1334
  datos_ingresos = []
1335
  for ciudad, data in cities_data.items():
1336
  nombre = normalizar_nombres_ciudades(ciudad)
1337
+ df = procesar_dataframe(data['ingresos_periodo'], ["Periodo", "Total", "Hombres", "Mujeres"])
 
1338
  if not df.empty:
1339
  df['Ciudad'] = nombre
1340
  datos_ingresos.append(df)
1341
 
1342
  if datos_ingresos:
1343
  df_ingresos = pd.concat(datos_ingresos)
1344
+ fig_ingresos = crear_grafico_barras_anual(
1345
+ df_ingresos,
1346
+ 'Evoluci贸n Anual de Ingresos Promedio por Ciudad',
1347
+ 'Ingresos (Soles)',
1348
+ 'Total',
1349
+ px.colors.sequential.Viridis
 
 
 
 
 
 
1350
  )
1351
  figs.append(fig_ingresos)
1352
  else:
1353
  figs.append(go.Figure())
1354
 
1355
+ # 3. Evoluci贸n de Brecha Salarial
1356
  datos_brecha = []
1357
  for ciudad, data in cities_data.items():
1358
  nombre = normalizar_nombres_ciudades(ciudad)
1359
+ df = procesar_dataframe(data['ingresos_periodo'], ["Periodo", "Total", "Hombres", "Mujeres"])
 
1360
  if not df.empty:
1361
  df['Brecha'] = (df['Hombres'] - df['Mujeres']) / df['Hombres'].replace(0, np.nan) * 100
1362
  df['Ciudad'] = nombre
 
1364
 
1365
  if datos_brecha:
1366
  df_brecha = pd.concat(datos_brecha)
1367
+ fig_brecha = crear_grafico_barras_anual(
1368
+ df_brecha,
1369
+ 'Evoluci贸n Anual de la Brecha Salarial por Ciudad',
1370
+ 'Brecha Salarial (%)',
1371
+ 'Brecha',
1372
+ px.colors.diverging.RdYlGn
 
 
 
 
 
 
 
 
 
 
 
1373
  )
1374
  figs.append(fig_brecha)
1375
  else:
 
1401
  with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue"), css="""
1402
  .gradio-container {background-color: #f8f9fa}
1403
  .plot-container {margin: 20px 0}
1404
+ .column-container {gap: 15px}
1405
  """) as app:
1406
 
1407
  gr.Markdown("# 馃搳 Dashboard Anal铆tico del Mercado Laboral Peruano")
 
1415
  )
1416
 
1417
  with gr.Tab("An谩lisis por Ciudad"):
1418
+ # Primera fila: Radar plot
1419
  with gr.Row():
1420
+ radar_plot = Plot(label="Radar de Indicadores Laborales")
1421
+
1422
+ # Segunda fila: 2 columnas para los dem谩s gr谩ficos
 
 
 
 
 
 
1423
  with gr.Row():
1424
+ with gr.Column(elem_classes="column-container"):
1425
+ desempleo_plot = Plot(label="Tasa de Desempleo")
1426
+ ingresos_plot = Plot(label="Ingresos Promedio")
1427
+ informalidad_plot = Plot(label="Tasa de Informalidad")
1428
+
1429
+ with gr.Column(elem_classes="column-container"):
1430
+ actividad_plot = Plot(label="Tasa de Actividad")
1431
+ brecha_plot = Plot(label="Brecha Salarial")
1432
 
1433
  with gr.Tab("An谩lisis Comparativo"):
1434
  with gr.Row():
1435
  global_desempleo = Plot(label="Ranking de Desempleo")
1436
  with gr.Row():
1437
+ global_ingresos = Plot(label="Evoluci贸n Anual de Ingresos")
1438
  with gr.Row():
1439
+ global_brecha = Plot(label="Evoluci贸n Anual de Brecha Salarial")
1440
  with gr.Row():
1441
+ global_btn = gr.Button("Actualizar An谩lisis", variant="primary")
1442
 
1443
+ # Eventos (se mantienen igual)
1444
  ciudad.change(
1445
  fn=actualizar_graficos,
1446
  inputs=ciudad,
1447
+ outputs=[radar_plot, desempleo_plot, ingresos_plot, informalidad_plot, actividad_plot, brecha_plot]
1448
  )
1449
 
1450
  global_btn.click(