hedtorresca commited on
Commit
c756b03
·
verified ·
1 Parent(s): cadca84

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +67 -25
app.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import pandas as pd
2
  import csv
3
  import plotly.express as px
@@ -5,10 +6,7 @@ import gradio as gr
5
  import folium
6
  from folium.plugins import MarkerCluster
7
 
8
- # Carga de datos
9
- df = pd.read_excel("Base de Datos Prueba.xlsx", parse_dates=["FECHA_APERTURA"])
10
-
11
- # Carga de metadatos de oficinas
12
  def load_offices_csv(path):
13
  with open(path, encoding='latin-1') as f:
14
  sample = ''.join([next(f) for _ in range(10)])
@@ -19,10 +17,23 @@ def load_offices_csv(path):
19
  df_off.columns = [c.strip() for c in df_off.columns]
20
  return df_off
21
 
22
- off_meta = load_offices_csv("oficinas_completas_deduccion_avanzada.csv")
 
 
 
 
 
 
 
23
 
24
- # Listas para UI
25
- zonas = sorted(off_meta['ZONA'].dropna().astype(str).unique().tolist())
 
 
 
 
 
 
26
 
27
  # Coordenadas hard-coded
28
  office_coords = {
@@ -255,44 +266,75 @@ office_coords = {
255
  "Zipaquira": (5.025810, -73.991283),
256
  }
257
 
258
- # Callback para filtrar oficinas según zona
259
  def update_oficinas(zona):
260
  if zona:
261
- return sorted(off_meta[off_meta['ZONA']==zona]['NOMBRE OFICINA'].dropna().astype(str).unique().tolist())
262
- return []
 
263
 
264
- # Función del dashboard
265
- def dashboard(ofis):
266
  d = df.copy()
 
 
267
  if ofis:
268
  d = d[d['OFICINA'].isin(ofis)]
269
- # Gráfico de distribución por producto
270
- fig1 = px.histogram(d, x='TIPO PRODUCTO', title='Distribución por producto')
271
- # Mapa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  m = folium.Map(location=[4.6, -74.1], zoom_start=6)
273
  mc = MarkerCluster().add_to(m)
274
- for ofi in ofis or []:
275
  coord = office_coords.get(ofi)
276
  if coord:
277
  total = d[d['OFICINA']==ofi]['MONTO_I'].sum()
278
- folium.CircleMarker(location=coord, radius=5,
279
  popup=f"{ofi}<br>Total: {total:,.0f} COP").add_to(mc)
280
  map_html = m._repr_html_()
281
- return fig1, map_html
282
 
283
  # Interfaz Gradio
284
  with gr.Blocks() as demo:
285
- gr.Markdown('## Dashboard Simplificado: Filtro por Zona y Oficina')
286
  with gr.Row():
287
  with gr.Column(scale=1):
288
- zona = gr.Dropdown(zonas, label='Zona')
289
- ofis = gr.Dropdown([], label='Oficina', multiselect=True)
290
- btn = gr.Button('Actualizar')
 
 
 
 
 
291
  with gr.Column(scale=3):
292
- plot = gr.Plot()
293
- mapa = gr.HTML()
 
 
 
 
 
294
  zona.change(update_oficinas, inputs=[zona], outputs=[ofis])
295
- btn.click(dashboard, inputs=[ofis], outputs=[plot, mapa])
 
296
 
297
  if __name__ == '__main__':
298
  demo.launch()
 
1
+ import os
2
  import pandas as pd
3
  import csv
4
  import plotly.express as px
 
6
  import folium
7
  from folium.plugins import MarkerCluster
8
 
9
+ # Función para cargar CSV de oficinas
 
 
 
10
  def load_offices_csv(path):
11
  with open(path, encoding='latin-1') as f:
12
  sample = ''.join([next(f) for _ in range(10)])
 
17
  df_off.columns = [c.strip() for c in df_off.columns]
18
  return df_off
19
 
20
+ # 1. Cargar y preparar datos
21
+ DATA_XLSX = "Base de Datos Prueba.xlsx"
22
+ OFFICES_CSV = "oficinas_completas_deduccion_avanzada.csv"
23
+
24
+ df = pd.read_excel(DATA_XLSX, parse_dates=["FECHA_APERTURA"])
25
+ df["MES"] = df["FECHA_APERTURA"].dt.to_period("M").dt.to_timestamp()
26
+
27
+ off_meta = load_offices_csv(OFFICES_CSV)
28
 
29
+ # Listas de filtros (sin departamento ni municipio)
30
+ zonas = sorted(off_meta['ZONA'].dropna().astype(str).unique().tolist())
31
+ oficinas = sorted(off_meta['NOMBRE OFICINA'].dropna().astype(str).unique().tolist())
32
+ productos = sorted(df['TIPO PRODUCTO'].dropna().astype(str).unique().tolist())
33
+ colaboradores = sorted(df['SK_COLABORADOR'].dropna().astype(str).unique().tolist())
34
+ segmentos = sorted(df['SEGMENTO_CLIENTE'].dropna().astype(str).unique().tolist())
35
+ min_amt, max_amt = int(df['MONTO_I'].min()), int(df['MONTO_I'].max())
36
+ min_plazo, max_plazo = int(df['PLAZO'].min()), int(df['PLAZO'].max())
37
 
38
  # Coordenadas hard-coded
39
  office_coords = {
 
266
  "Zipaquira": (5.025810, -73.991283),
267
  }
268
 
269
+ # Callback para filtrar oficinas según zona directamente (ya no hay dept/muni)
270
  def update_oficinas(zona):
271
  if zona:
272
+ return sorted(off_meta[off_meta['ZONA']==zona]['NOMBRE OFICINA']
273
+ .dropna().astype(str).unique().tolist())
274
+ return oficinas
275
 
276
+ # Dashboard
277
+ def dashboard(zona, ofis, tipos_sel, colabor_sel, plazo_rango, segmento_sel, monto_rango):
278
  d = df.copy()
279
+ if zona:
280
+ d = d[d['ZONA']==zona]
281
  if ofis:
282
  d = d[d['OFICINA'].isin(ofis)]
283
+ if tipos_sel:
284
+ d = d[d['TIPO PRODUCTO'].isin(tipos_sel)]
285
+ if colabor_sel:
286
+ d = d[d['SK_COLABORADOR'].isin(colabor_sel)]
287
+ if segmento_sel:
288
+ d = d[d['SEGMENTO_CLIENTE'].isin(segmento_sel)]
289
+ d = d[(d['PLAZO'] >= plazo_rango[0]) & (d['PLAZO'] <= plazo_rango[1])]
290
+ d = d[(d['MONTO_I'] >= monto_rango[0]) & (d['MONTO_I'] <= monto_rango[1])]
291
+
292
+ fig1 = px.bar(d.groupby('MES')['MONTO_I'].sum().reset_index(), x='MES', y='MONTO_I',
293
+ labels={'MES':'Mes','MONTO_I':'Monto (COP)'}, title='Monto por mes')
294
+ fig2 = px.pie(d['TIPO PRODUCTO'].value_counts().reset_index().rename(columns={'index':'TIPO PRODUCTO',0:'CANT'}),
295
+ names='TIPO PRODUCTO', values='CANT', title='Distribución por producto')
296
+ fig3 = px.box(d, x='TIPO PRODUCTO', y='TASA', title='Distribución de tasas')
297
+ df_col = d['SK_COLABORADOR'].value_counts().reset_index().rename(columns={'index':'Colaborador',0:'CANT'})
298
+ fig4 = px.bar(df_col.head(10), x='Colaborador', y='CANT', title='Top 10 colaboradores')
299
+ fig5 = px.histogram(d, x='PLAZO', nbins=20, title='Distribución de plazo (días)')
300
+ df_seg = d['SEGMENTO_CLIENTE'].value_counts().reset_index().rename(columns={'index':'Segmento',0:'CANT'})
301
+ fig6 = px.bar(df_seg, x='Segmento', y='CANT', title='Distribución por segmento')
302
+
303
  m = folium.Map(location=[4.6, -74.1], zoom_start=6)
304
  mc = MarkerCluster().add_to(m)
305
+ for ofi in ofis or oficinas:
306
  coord = office_coords.get(ofi)
307
  if coord:
308
  total = d[d['OFICINA']==ofi]['MONTO_I'].sum()
309
+ folium.CircleMarker(location=coord, radius=6, fill=True,
310
  popup=f"{ofi}<br>Total: {total:,.0f} COP").add_to(mc)
311
  map_html = m._repr_html_()
312
+ return fig1, fig2, fig3, fig4, fig5, fig6, map_html
313
 
314
  # Interfaz Gradio
315
  with gr.Blocks() as demo:
316
+ gr.Markdown('## Dashboard Bancamía Filtros de Zona y Oficina')
317
  with gr.Row():
318
  with gr.Column(scale=1):
319
+ zona = gr.Dropdown(zonas, label='Zona')
320
+ ofis = gr.Dropdown(oficinas, label='Oficina', multiselect=True)
321
+ tipos_sel = gr.CheckboxGroup(productos, label='Tipo de producto')
322
+ colabor_sel = gr.Dropdown(colaboradores, label='Colaborador', multiselect=True)
323
+ plazo_rango = gr.Slider(min_plazo, max_plazo, value=[min_plazo, max_plazo], label='Plazo (días)')
324
+ segmento_sel = gr.Dropdown(segmentos, label='Segmento', multiselect=True)
325
+ monto_rango = gr.Slider(min_amt, max_amt, value=[min_amt, max_amt], step=1000000, label='Monto (COP)')
326
+ btn = gr.Button('Actualizar')
327
  with gr.Column(scale=3):
328
+ out1 = gr.Plot()
329
+ out2 = gr.Plot()
330
+ out3 = gr.Plot()
331
+ out4 = gr.Plot()
332
+ out5 = gr.Plot()
333
+ out6 = gr.Plot()
334
+ out7 = gr.HTML()
335
  zona.change(update_oficinas, inputs=[zona], outputs=[ofis])
336
+ btn.click(dashboard, inputs=[zona, ofis, tipos_sel, colabor_sel, plazo_rango, segmento_sel, monto_rango],
337
+ outputs=[out1, out2, out3, out4, out5, out6, out7])
338
 
339
  if __name__ == '__main__':
340
  demo.launch()