aliskairraul commited on
Commit
9f5cca2
·
0 Parent(s):

Proyecto Lab-2 Primer Commit

Browse files
.gitignore ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ # Excluir el entorno virtual de Python
2
+ venv/
3
+
4
+ # Excluir el archivo .flake8
5
+ .flake8
6
+
7
+ # Excluir todas las carpetas __pycache__
8
+ __pycache__/
README.md ADDED
@@ -0,0 +1,290 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div style="text-align: center; border-top: 1px solid #ccc; border-bottom: 1px solid #ccc; padding: 10px 0;">
2
+ <h1 style="color: lightblue; font-size: 2em;">Proyecto Labs 2</h1>
3
+ </div>
4
+
5
+ ## Descripción
6
+
7
+ <p style="text-align: justify; text-indent: 2em;">
8
+ Este proyecto se centra en un exhaustivo análisis del sector de las telecomunicaciones en Argentina, utilizando datos extraídos del Ente Nacional de Comunicaciones (ENACOM). Se a estudiado la evolución de los ingresos y la penetración de mercado en los sectores de Telefonía Fija, Telefonía Móvil, Internet y Televisión, a lo largo de la última década.</p>
9
+
10
+ <p style="text-align: justify; text-indent: 2em;">
11
+ EL análisis se profundiza especialmente en el sector de Internet, donde se examinó el comportamiento del mercado en relación con las tecnologías que brindan el servicio, tales como ADSL, WIRELESS, Fibra Óptica y Cable Modem, y las Velocidades Medias de Descargas, tanto a nivel Nacional como de Provincias.</p>
12
+
13
+ <p style="text-align: justify; text-indent: 2em;">
14
+ Para una mejor comprensión del comportamiento del sector se empleo el uso de dos(2) KPI's a nivel de Provincias y tres(3) Métricas Nacionales, todas ellas de seguimiento trimestral.</p>
15
+
16
+ <p style="text-align: justify; text-indent: 2em;">
17
+ Los KPI empleados fueron:</p>
18
+
19
+ - **Crecimiento Trimestral de 2% en el número de Accesos por cada 100 Hogares por Provincia**:
20
+ <p style="text-align: justify; text-indent: 2em;">
21
+ Donde el Objetivo para el siguiente Trimestre se fijará simplemente añadiendo un 2% a los accesos por cada 100 Hogares del trimestre actual. Y cuando lleguemos en el tiempo al siguiente trimestre, la Medición del cumplimiento de dicho objetivo sería de la siguiente manera:</p>
22
+ <br>
23
+
24
+ $$
25
+ \text{Cumplimiento KPI} = \left( \frac{\text{Acc 100 Hog Trim}}{\text{Objetivo KPI}} \right) \times 100
26
+ $$
27
+
28
+ <br>
29
+ <br>
30
+ - **Crecimiento Trimestral de 5% en la Velocidad Media de Bajada por Provincia**:
31
+ <p style="text-align: justify; text-indent: 2em;">
32
+ Donde el Objetivo para el siguiente Trimestre se fijará simplemente añadiendo un 5% a la velocidad del Trimestre actual. Y cuando lleguemos en el tiempo al siguiente trimestre, la Medición del cumplimiento de dicho objetivo sería de la siguiente manera:</p>
33
+ <br>
34
+
35
+ $$
36
+ \text{Cumplimiento KPI} = \left( \frac{\text{Vel Mbps Trim}}{\text{Objetivo KPI}} \right) \times 100
37
+ $$
38
+
39
+ <br>
40
+ <br>
41
+ <p style="text-align: justify; text-indent: 2em;">
42
+ Las Métricas utilizadas fueron:</p>
43
+
44
+ - **Variación Trimestral del número de Accesos por cada 100 Hogares en el País**:
45
+ <p style="text-align: justify; text-indent: 2em;">
46
+ El cálculo de la métrica se realiza de la siguiente manera:</p>
47
+ <br>
48
+
49
+ $$
50
+ \text{Var Accesos 100 Hog} = \left( \frac{\text{Accesos Trimestre}}{\text{Accesos Trimestre Anterior}} - 1 \right) \times 100
51
+ $$
52
+
53
+ <br>
54
+ <br>
55
+ - **Variación Trimestral de la Velocidad Media de Bajada en el País**:
56
+ <p style="text-align: justify; text-indent: 2em;">
57
+ El cálculo de la métrica se realiza de la siguiente manera:</p>
58
+ <br>
59
+
60
+ $$
61
+ \text{Var Mbps} = \left( \frac{\text{Vel Mbps Trim}}{\text{Vel Mbps Trim Anterior}} - 1 \right) \times 100
62
+ $$
63
+
64
+ <br>
65
+ <br>
66
+ - **Total de Accesos en el País**:
67
+ <p style="text-align: justify; text-indent: 2em;">
68
+ Simplemente se monitorea el <b>Total de Accesos en el país en el Trimestre en curso</b>
69
+ <br>
70
+
71
+ <p style="text-align: justify; text-indent: 2em;">
72
+ Para facilitar la comprensión y visualización de los datos, desarrollamos una herramienta interactiva utilizando Python y el framework Dash de la librería Plotly. Esta herramienta permite a los usuarios explorar los datos de manera intuitiva y obtener insights valiosos.</p><br>
73
+ <br>
74
+ <image src='assets/capture_tooltip.png'><br>
75
+ <br>
76
+ <image src='assets/capture_mapa_oportunidades.png'><br>
77
+ <br>
78
+
79
+ <p style="text-align: justify; text-indent: 2em;">
80
+ Previo al análisis, normalizamos los datos y creamos un modelo de datos en SQL (EDR) funcional para la empresa, que sirve como un data warehouse. Este modelo no solo organiza los datos de manera eficiente, sino que también está diseñado para soportar futuros estudios y análisis. EL EDR creado se puede observar en la siguiente Imagen<br></p>
81
+ <br>
82
+
83
+ <image src='noteboocks/assets/edr.png'>
84
+
85
+ <p style="text-align: justify; text-indent: 2em;">
86
+ Este proyecto no sdlo demuestra habilidades técnicas en análisis de datos y visualización, sino también una comprensión profunda del sector de telecomunicaciones y la capacidad de transformar datos complejos en información útil para la toma de decisiones estratégicas.</p>
87
+
88
+ ## Tabla de contenido
89
+
90
+ 1. [Descripción](#descripción)
91
+ 1. [Enlaces](#enlaces)
92
+ 1. [Instalación y Requisitos](#instalación-y-requisitos)
93
+ 1. [Estructura del Proyecto](#estructura-del-proyecto)
94
+ 1. [Uso y Ejecución](#uso-y-ejecución)
95
+ 1. [Datos y Fuentes](#datos-y-fuentes)
96
+ 1. [Metodología](#metodología)
97
+ 1. [Conclusiones y Recomendaciones](#resultados-y-conclusiones)
98
+ 1. [Autores](#autores)
99
+
100
+ ## Enlaces
101
+
102
+ - **Enlace al repositorio**
103
+ - https://github.com/aliskairraul/Bootcamp-Henry-Proyecto-Lab_2.git
104
+
105
+ ## Instalación y Requisitos
106
+
107
+ **Requisitos:**
108
+
109
+ - Requisitos para la app
110
+
111
+ - Python 3.10
112
+ - dash==2.16.1
113
+ - dash_daq==0.5.0
114
+ - pandas==2.2.2
115
+ - plotly==5.21.0
116
+ - polars==1.2.1
117
+ - pyarrow==17.0.0
118
+
119
+ - Requisitos para los Notebooks
120
+ - Python 3.10
121
+ - jupyter==1.1.1
122
+ - pandas==2.2.2
123
+ - polars==1.7.1
124
+ - plotly==5.24.1
125
+ - fastexcel==0.11.6
126
+ - duckdb==1.1.0
127
+ - pyarrow==17.0.0
128
+ - sqlalchemy==2.0.35
129
+ - PyMySQL==1.1.1
130
+
131
+ **Pasos de instalación:**
132
+
133
+ 1. Clonar el repositorio: `git clone https://github.com/aliskairraul/Bootcamp-Henry-Proyecto-Lab_2.git`
134
+ 2. Partamos del echo de que esto debe tratarse como 2 sub-proyectos por separado (un Análisis y una Aplicación realizada en Dash). Cree dos carpetas dentro de su ordenador
135
+
136
+ - Una Carpeta va todo lo referente al análisis y el modelo (Allí va a copiar sólo la Carpeta `notebooks` de este repositorio)
137
+ - En la otra Carpeta tendrá todo lo referente a la App de Dash (Allí va `TODO el Repositorio, excepto la Carpeta notebooks`)
138
+
139
+ 4. Crear un entorno virtual en cada carpeta: `python3.10 -m venv nombre_del_entorno`
140
+ 5. El Archivo `requirements.txt` en la raiz del proyecto son las dependencias para la App realizada en Dash y es el que debe usar para la carpeta en que tenga dicha App
141
+ 6. El Archivo `requirements.txt` que se encuentra dentro de la carpeta `notebooks` es el que debe usar para instalar las dependencias del análisis
142
+ 7. Activar en cada proyecto el entorno virtual:
143
+ - Windows: `nombre_del_entorno\Scripts\activate`
144
+ - macOS/Linux: `source nombre_del_entorno/bin/activate`
145
+ 8. Instalar las dependencias: `pip install -r requirements.txt`
146
+
147
+ ## Estructura del Proyecto
148
+
149
+ 1. **Para la parte del Análisis**<br>
150
+
151
+ - `notebooks/`
152
+ - Incluye los siguiente:
153
+ - `assets/`
154
+ - Imagenes ilustrativas.
155
+ - `tablas/`
156
+ - Aca se guardaran los archivos con estructura similar al EDR de la descripción del proyecto.
157
+ - `tablas_dash/`
158
+ - Aca se guardaran tablas especialmenete creadas para darle velocidad a la herramienta de visualización cuando interactúe con el usuario.
159
+ - `db/`
160
+ - Contiene los siguientes archivos:
161
+ - `db/connection.py` Se encarga de la conección con la Base de datos Mysql
162
+ - `db/tables.py` Tiene TODA la estructura del EDR desarrollada en el ORM SqlAlchemy de Python. Funcional para cualquier motor de base de datos SQL, contiene Todas las tablas y sus relaciones.
163
+ - `db/create_tables.py` Script de Python que al ejecutarlo crea la base de tablas y relaciones de la Base de datos
164
+ - `docker/`
165
+ - contiene los siguientes archivos
166
+ - `docker/Dockerfile` Dockerfile de la imagen Mysql
167
+ - `docker/pasos_en_la_terminal.txt` Explicación de lo concerniente a Docker y Mysql
168
+ - `utils/`
169
+ -Contiene archivos con extensión `.py` que tienen funciones que dan soporte a los cuadernos Jupyter notebooks.
170
+ - `01_normalizando_internet.ipynb`
171
+ - Normalización de los datos contenidos en el archivo Internet.xlsx
172
+ - `02_normalizando_otros.ipynb`
173
+ - Normalización de los datos contenidos en los archivos
174
+ - Telefonia_fija.xlsx
175
+ - Telefonia_movil.xlsx
176
+ - Television.xlsx
177
+ - `03_creando_data_tablero.ipynb`
178
+ - Donde se crean unas tablas customizadas para la herramineta de Visualización
179
+ - `04_eda_comparando_tecnologias.ipynb`
180
+ - Análisis de la evolución de los distintos sectores de las telecomunicaciones
181
+ - `05_eda_internet.ipynb`
182
+ - Análisis enfocado en el sector Internet de las telecomunicaciones
183
+
184
+ 2. **Para la parte de la App Dash - Herramineta de Visualización**
185
+
186
+ - `data/`: Contiene los archivos `parquet` necesarios para la visualización.
187
+ - `components/`: Carpeta donde se guardan los archivos `.py ` que contienen los distintos componentes de la visualización.
188
+ - `utils/` Guarda un archivo `.py` donde se realizan unos filtros necesarios en la visualización del Mapa de Oportunidades.
189
+ - `main.py` Arhivo raiz de la App de Dash
190
+ - `requirements.txt` dependencias necesarias para la App
191
+ - `README.md`: Archivo de documentación del proyecto.
192
+
193
+ ## Uso y Ejecución
194
+
195
+ 1. **Para la parte del Análisis**:
196
+
197
+ - Ejecute los siguientes archivos en el Orden que se nombran a continuación:
198
+ - `01_normalizando_internet.ipynb`
199
+ - `02_normalizando_otros.ipynb`
200
+ - `03_creando_data_tablero.ipynb`
201
+ - `04_eda_comparando_tecnologias.ipynb`
202
+ - `05_eda_internet.ipynb`
203
+
204
+ 2. **Para la parte de la App de Dash, la Visualización**:
205
+
206
+ - Asegurese de que la estructura de este repositorio, a excepción de la Carpeta `notebooks`, se copió Integramente en la locación de su computador que dispuso para ello.
207
+ - Con el entorno virtual activado ejecute `python main:app` espere que se ejecute y desde el navegador `http://127.0.0.1:8050` para que vaya directamente en la visualización desde su navegador.
208
+
209
+ ## Datos y Fuentes
210
+
211
+ <p style="text-align: justify; text-indent: 2em;">
212
+ Los Datasets Iniciales fueron extraídos de la del Ente Nacional de Comunicaciones (ENACOM) de Argentina, en su gran Mayoria, sólo el archivo <b>tipos-de-cambio-historicos.csv</b> no viene de allí, este se saco de la pagina del Banco Central de Argentina.
213
+ </p>
214
+ <br>
215
+
216
+ ## Metodología
217
+
218
+ 1. **Recolección de Datos**
219
+ <p style="text-align: justify; text-indent: 2em;">
220
+ Los datos utilizados en este proyecto fueron extraídos del Ente Nacional de Comunicaciones (ENACOM) de Argentina. Se recopilaron datos históricos de los últimos diez años sobre los ingresos y la penetración de mercado en los sectores de Telefonía Fija, Telefonía Móvil, Internet y Televisión.
221
+ </p>
222
+
223
+ 2. **Normalización de Datos**
224
+ <p style="text-align: justify; text-indent: 2em;">
225
+ Antes de proceder con el análisis, se normalizaron los datos para asegurar su consistencia y precisión. Este proceso incluyó la limpieza de datos, la eliminación de duplicados y la corrección de valores Nulos.
226
+ </p>
227
+
228
+ 3. **Creación del Modelo de Datos (EDR)**
229
+ <p style="text-align: justify; text-indent: 2em;">
230
+ Se diseñó y creó un modelo de datos en SQL (EDR) que sirve como data warehouse para la empresa. Este modelo organiza los datos de manera eficiente y está preparado para soportar futuros estudios y análisis.
231
+ </p>
232
+
233
+ 4. **Análisis de Datos**
234
+ <p style="text-align: justify; text-indent: 2em;">
235
+ El análisis se centró en la evolución de los ingresos y la penetración de mercado en los sectores mencionados. Se realizó un estudio detallado del sector de Internet, examinando el comportamiento del mercado en relación con las tecnologías que brindan el servicio, tales como ADSL, WIRELESS, Fibra Óptica y Cable Modem y las distintas Velocidades Medias de Bajada que presentan las conexiones.
236
+ </p>
237
+
238
+ 5. **Definición de KPI’s y Métricas**
239
+ <p style="text-align: justify; text-indent: 2em;">
240
+ Para una mejor comprensión del comportamiento del sector, se definieron dos KPI’s a nivel de provincias y tres métricas nacionales, todas ellas de seguimiento trimestral, y se encuentran a detalle en la parte de <b>Descripción</b> de este Documento
241
+ </p>
242
+
243
+ 6. **Visualización de Datos**
244
+ <p style="text-align: justify; text-indent: 2em;">
245
+ Se desarrolló una herramienta interactiva de visualización utilizando Python y el framework Dash de la librería Plotly. Esta herramienta permite a los usuarios explorar los datos de manera intuitiva y obtener insights valiosos.
246
+ </p>
247
+
248
+ 7. **Documentación y Presentación**
249
+ <p style="text-align: justify; text-indent: 2em;">
250
+ Finalmente, se documentaron todos los procesos y resultados del análisis. La documentación incluye la descripción del modelo de datos, los métodos de análisis utilizados, y las visualizaciones generadas. Esta documentación está diseñada para ser clara y accesible, facilitando su uso por parte de otros analistas y compañeros dentro de la Empresa.
251
+ </p>
252
+
253
+ ## Conclusiones
254
+
255
+ 1. **Impacto de la Inflación y Devaluación**:
256
+ <p style="text-align: justify; text-indent: 2em;">
257
+ La comparación de la evolución del mercado en dólares y pesos Argentinos muestra resultados significativamente diferentes, lo que sugiere la presencia de inflación y/o devaluación durante el período estudiado. Es crucial consultar con economistas y expertos locales antes de realizar inversiones para comprender mejor la situación económica actual.
258
+ </p>
259
+
260
+ 2. **Reducción de Ingresos en el Sector de Telecomunicaciones**:
261
+ <p style="text-align: justify; text-indent: 2em;">
262
+ En la última década, los ingresos en dólares de los distintos sectores de telecomunicaciones se han reducido a la mitad. El sector de Internet es el único que ha experimentado una caída leve en ingresos, mientras que su penetración en el mercado ha seguido aumentando. Sin embargo, no se dispone de datos sobre los costos de masificación de estas tecnologías, lo que limita el análisis completo del sector.
263
+ </p>
264
+
265
+ 3. **Preferencias del Mercado**:
266
+ <p style="text-align: justify; text-indent: 2em;">
267
+ Los datos indican una clara preferencia de los consumidores argentinos por servicios de Internet que ofrecen mayores velocidades. Esto se refleja en la disminución drástica de la participación de mercado de la tecnología ADSL y el aumento en la velocidad media de bajada de Internet en los últimos tres años. Las tecnologías dominantes en el mercado actual son CableModem y Fibra Óptica, aunque ambas requieren infraestructura de cableado, lo que puede no ser rentable en áreas de baja densidad poblacional.
268
+ </p>
269
+
270
+ ## Recomendaciones
271
+
272
+ 1. **Consulta con Expertos Económicos**:
273
+ <p style="text-align: justify; text-indent: 2em;">
274
+ Antes de realizar inversiones en el sector de telecomunicaciones en Argentina, es recomendable consultar con economistas y expertos locales para obtener una comprensión detallada de la situación económica y los posibles riesgos asociados.
275
+ </p>
276
+
277
+ 2. **Análisis de Costo-Beneficio**:
278
+ <p style="text-align: justify; text-indent: 2em;">
279
+ Realizar un análisis de costo-beneficio detallado del sector de Internet es esencial antes de incursionar en él. Esto ayudará a identificar las oportunidades y desafíos específicos del mercado y a tomar decisiones informadas.
280
+ </p>
281
+
282
+ 3. **Exploración de Tecnologías Inalámbricas**:
283
+ <p style="text-align: justify; text-indent: 2em;">
284
+ Dado que las tecnologías CableModem y Fibra Óptica tienen limitaciones en áreas de baja densidad poblacional, se recomienda estudiar la viabilidad de tecnologías inalámbricas de alta velocidad, como la tecnología satelital, para penetrar en estos mercados. Esto podría representar una gran oportunidad para expandir la cobertura de Internet en localidades con menor número de habitantes.
285
+ </p>
286
+
287
+ ## Autores:
288
+
289
+ Este proyecto fue realizado por: Aliskair Rodríguez.<br>
290
+ [linkedin.com/in/aliskair-rodriguez-782b3641](https://www.linkedin.com/in/aliskair-rodriguez-782b3641/)
assets/styles.css ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ body {
2
+ background-color: rgb(30, 30, 30);
3
+ }
4
+
5
+ .work_container {
6
+ width: 98vw;
7
+ height: 93vh;
8
+ display: flex;
9
+ justify-content: space-around;
10
+ }
11
+
12
+ .tab_subcontainers{
13
+ margin-top: 1em;
14
+ height: 97%;
15
+ background-color: #2b2b2b;
16
+ border: 0.05em solid #656565;
17
+ border-radius: 0.5em;
18
+ }
19
+
20
+ /* TAB HOME */
21
+ #tab_home{
22
+ display: flex;
23
+ flex-direction: column;
24
+ justify-content: space-around;
25
+ width: 99%;
26
+ }
27
+
28
+ #title_home{
29
+ margin-top: 3%;
30
+ text-align: center;
31
+ color: #ffffff;
32
+ font-weight: bold;
33
+ font-size: 3.5rem;
34
+ }
35
+
36
+ .pestanas{
37
+ font-weight: bold;
38
+ font-size: 1.75rem;
39
+ }
40
+
41
+ .textos_pestanas{
42
+ font-weight: normal;
43
+ font-size: 1.5rem;
44
+ }
45
+
46
+ .home-content {
47
+ background-color: #2b2b2b;
48
+ padding: 2%;
49
+ color: #ffffff;
50
+ border: 1px solid #ccc;
51
+ border-radius: 5px;
52
+ }
53
+
54
+
55
+
56
+
57
+
58
+ /* TAB 2 */
59
+ #tab2_left{
60
+ width: 20%;
61
+ }
62
+
63
+ #tab2_right{
64
+ width: 78%;
65
+ text-align: center;
66
+ }
67
+
68
+ #title_right_tab2{
69
+ margin-top: 0.5rem;
70
+ display: inline-block;
71
+ width: 100%;
72
+ height: 10%;
73
+ color: #ffffff;
74
+ font-weight: bold;
75
+ font-size: 1.5rem;
76
+ }
77
+
78
+ #grafico_right_tab2{
79
+ width: 100%;
80
+ height: 89%;
81
+ }
82
+
83
+ #container_graficos_tab2{
84
+ width: 100%;
85
+ height: 100%;
86
+ }
87
+
88
+ #container_control_slides{
89
+ width: 100%;
90
+ display: flex;
91
+ justify-content: space-around;
92
+ color: #ffffff;
93
+ font-weight: bold;
94
+ font-size: 1.5rem;
95
+ }
96
+
97
+ .parrafo_left{
98
+ margin-left: 2%;
99
+ margin-right: 2%;
100
+ color: #ffffff;
101
+ /* font-weight: bold; */
102
+ }
103
+
104
+
105
+ /* TAB 3 */
106
+ #tab3_right{
107
+ /* margin-top: 1em; */
108
+ display: flex;
109
+ flex-direction: column;
110
+ justify-content: space-between;
111
+ width: 99%;
112
+ height: 97%;
113
+ text-align: center;
114
+ }
115
+
116
+ #zona_tarjeta_tab3{
117
+ height: 18%;
118
+ display: flex;
119
+ justify-content: space-between;
120
+ }
121
+
122
+ #drop_tab3{
123
+ width: 24%;
124
+ height: 100%;
125
+ }
126
+
127
+
128
+ #tarjeta_1{
129
+ width: 24%;
130
+ height: 100%;
131
+ }
132
+
133
+ #tarjeta_2{
134
+ width: 24%;
135
+ height: 100%;
136
+ }
137
+
138
+ #tarjeta_3{
139
+ width: 24%;
140
+ height: 100%;
141
+ }
142
+
143
+ #zona_grafica_tab3{
144
+ height: 80%;
145
+ display: flex;
146
+ justify-content:space-between;
147
+ }
148
+
149
+ #zona_barras_tab3{
150
+ width: 60%;
151
+ height: 100%;
152
+ }
153
+
154
+ #barras_tab3{
155
+ width: 100%;
156
+ height: 100%;
157
+ }
158
+
159
+ #zona_pies_tab3{
160
+ width: 39%;
161
+ height: 100%;
162
+ }
163
+
164
+ #pies_tab3{
165
+ width: 100%;
166
+ height: 100%;
167
+ }
168
+
169
+ #grafico_rangos_tab3{
170
+ width: 60%;
171
+ height: 60%;
172
+ }
173
+
174
+ #label_periodo{
175
+ margin-top: 4%;
176
+ text-align: left;
177
+ font-size: 1.3rem;
178
+ }
179
+
180
+ #grafico_barras_tab3{
181
+ display: flex;
182
+ flex-direction: column;
183
+ justify-content: space-between;
184
+ }
185
+
186
+ .tarjetas{
187
+ color: #ffffff;
188
+ font-weight: bold;
189
+ font-size: 2.5rem;
190
+ }
191
+
192
+ #pie_pagina_tab3{
193
+ font-size: 1.2rem;
194
+ color: #ffffff;
195
+ }
196
+
197
+
198
+ /* TAB 4 */
199
+ #tab4_left{
200
+ width: 20%;
201
+ }
202
+
203
+ #tab4_center{
204
+ width: 37%;
205
+ }
206
+
207
+ #tab4_right{
208
+ width: 40%;
209
+ }
210
+
211
+ .one_drop_tab4{
212
+ width: 90%;
213
+ color: #ffffff;
214
+ font-weight: bold;
215
+ margin-left: 5%;
216
+ }
217
+
218
+ #tab4_rangos_response{
219
+ width: 100%;
220
+ text-align: center;
221
+ color: #ffffff;
222
+ font-weight: bold
223
+ }
224
+
225
+ #texto_tab4{
226
+ display: inline-block;
227
+ color: #ffffff;
228
+ font-weight: bold;
229
+ font-size: 1.3rem;
230
+
231
+
232
+ }
233
+
234
+ #tab4_texto_resultados{
235
+ width: 100%;
236
+ text-align: center;
237
+ }
238
+
239
+ #contenedor_pies_tab4{
240
+ margin-top: 2%;
241
+ text-align: center;
242
+ }
243
+
244
+
245
+ /* LETRAS DROPS */
246
+
247
+ .title_left{
248
+ margin-top: 3%;
249
+ text-align: center;
250
+ color: #ffffff;
251
+ font-weight: bold;
252
+ font-size: 1.5rem;
253
+ }
254
+
255
+ .titles{
256
+ margin-top: 3%;
257
+ text-align: center;
258
+ /* color: #d2d0ce; */
259
+ color: #ffffff;
260
+ font-weight: bold;
261
+ font-size: 1.5rem;
262
+ }
263
+
264
+ .tab_left{
265
+ height: 100%;
266
+ width: 100%;
267
+ }
268
+
269
+ .btns{
270
+ display: inline-block;
271
+ /* background-color: #70cbff; */
272
+ background-color: #ffffff;
273
+ width: 30%;
274
+ height: 2rem;
275
+ border-radius: 0.3rem;
276
+ }
277
+
278
+ .btn-container{
279
+ width: 100%;
280
+ text-align: center;
281
+ }
components/component_home.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dash import html
2
+
3
+ component_home = html.Div([
4
+ html.Div([
5
+ html.Div([
6
+ html.Div(html.Label("Telecomunicaciones Argentina"), id='title_home'),
7
+ html.Br(),
8
+ html.Br(),
9
+ html.Br(),
10
+ html.Ul([
11
+ html.Li([
12
+ "¿Porqué Internet?:",
13
+ html.Ul([
14
+ html.Li("Análisis del comportamiento de las Distintas Tecnologías de Telecomunicación")
15
+ ], className='textos_pestanas')
16
+ ], id="contexto", className="pestanas"),
17
+ html.Br(),
18
+ html.Br(),
19
+ html.Li([
20
+ "Seguimiento a Métricas:",
21
+ html.Ul([
22
+ html.Li("Seguimiento a los Indicadores de Gestión Trimestrales del Internet")
23
+ ], className='textos_pestanas')
24
+ ], id="tablero", className="pestanas"),
25
+ html.Br(),
26
+ html.Br(),
27
+ html.Li([
28
+ "Mapa de Oportunidades:",
29
+ html.Ul([
30
+ html.Li("Mapa de seguimiento de Oportunidades por Rangos de Población")
31
+ ], className='textos_pestanas')
32
+ ], id="mapa", className="pestanas")
33
+ ])
34
+
35
+ ], className="home-content"),
36
+ ], id='tab_home'),
37
+ ], className='work_container', id='tab2_component')
components/component_tab2.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dash import html
2
+ from components.component_tab2_left import component_tab2_left
3
+
4
+
5
+ component_tab_2 = html.Div([
6
+ html.Div([component_tab2_left], className='tab_subcontainers', id='tab2_left'),
7
+ html.Div([
8
+ html.Div([], id='title_right_tab2'),
9
+ html.Div([], id='grafico_right_tab2'),
10
+ ], className='tab_subcontainers', id='tab2_right')
11
+ ], className='work_container', id='tab2_component')
components/component_tab2_grafico.py ADDED
@@ -0,0 +1,274 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import polars as pl
2
+ from dash import html, dcc
3
+ import plotly.express as px
4
+ import plotly.graph_objects as go
5
+ from plotly.subplots import make_subplots
6
+
7
+ internet_pais = pl.read_parquet('data/internet_tab2.parquet')
8
+ telefonia_movil = pl.read_parquet('data/telefonia_movil_tab2.parquet')
9
+ telefonia_fija = pl.read_parquet('data/telefonia_fija_tab2.parquet')
10
+ television = pl.read_parquet('data/television_tab2.parquet')
11
+ df_pies = pl.read_parquet('data/df_pie_tab2.parquet')
12
+ tecnologias_grafico_9 = pl.read_parquet('data/tecnologias_internet_graficos_tab2.parquet')
13
+ rangos_grafico_10 = pl.read_parquet('data/rangos_internet_graficos_tab2.parquet')
14
+
15
+ # Listas de Dataframes, Nombres de Graficos y Colores Para los Gráficos con 4 Lineas
16
+ dfs_4 = [internet_pais, telefonia_movil, telefonia_fija, television]
17
+ list_4 = ["Internet", "Telefonía Móvil", "Telefonía Fija", "Televisión"]
18
+ colors_4 = ['#22D3EE', '#38C172', '#F6993F', '#FFED4A']
19
+
20
+
21
+ # Listas de Datagrames, Nombres de Graficos y Colores Para los Gráficos con 3 Lineas
22
+ dfs_3 = [internet_pais, telefonia_fija, television]
23
+ list_3 = ["Internet", "Telefonía Fija", "Televisión"]
24
+ colors_3 = ['#22D3EE', '#F6993F', '#FFED4A']
25
+
26
+
27
+ # ESTA FUNCION CREA LAS GRAFICAS 1, 2 y 4 del Tab 2
28
+ def crear_grafica(df_list: list, y_column: str, list_names: list, colors: list) -> px.line:
29
+ """Crear gráfica: Función para crear gráficas de tendencias
30
+
31
+ Args:
32
+ df_list (list): Lista de Dataframes
33
+ y_column (str): Columna del dataframe a graficar
34
+ title (str): Título del gráfico
35
+ list_names (list): Lista de Nombres de los gráficos
36
+ colors (list): Lista de Colores
37
+
38
+ Returns:
39
+ px.line: Grafica de linea de la Libreria plotly
40
+ """
41
+ fig = px.line()
42
+ # Aca esto es como 3 ciclos for en paralelo cada variable
43
+ for df, name, color in zip(df_list, list_names, colors):
44
+ fig.add_scatter(x=df["fecha"], y=df[y_column], mode='lines', name=name, line=dict(color=color))
45
+
46
+ fig.update_layout(
47
+ xaxis_title='Periodo',
48
+ yaxis_title=y_column,
49
+ font=dict(color='#ffffff', size=16),
50
+ paper_bgcolor='rgba(0,0,0,0)',
51
+ plot_bgcolor='rgba(0,0,0,0)', # Fondo de la grilla transparente
52
+ xaxis=dict(showgrid=False, zeroline=True, linecolor='#ffffff'),
53
+ yaxis=dict(showgrid=False, zeroline=True, linecolor='#ffffff'),
54
+ height=600,
55
+ )
56
+ return fig
57
+
58
+
59
+ # ESTA SOLO HACE EL GRAFICO DE TORTAS DEL TAB 2
60
+ def crear_graf_pie(df: pl.DataFrame, colors: list):
61
+ """crear_graf_pie: Crea un Subplot de Pies de Plotly. Muestran la comparación
62
+ de ingresos en Dolares entre 2014 y 2024 en la Tab 2 "¿Porqué Internet?
63
+
64
+ Args:
65
+ df (pl.DataFrame): Dataframe con la información
66
+ colors (list): ancho del gráfico
67
+
68
+ Returns:
69
+ go.Fig: Suplots de Pies de la Libreria Plotly
70
+ """
71
+
72
+ fig = make_subplots(rows=1, cols=2, specs=[[{'type': 'pie'}, {'type': 'pie'}]],
73
+ subplot_titles=("Ingresos 2014", "Ingresos 2024"))
74
+
75
+ # Gráfico de Pie para Ingresos 2014
76
+ fig.add_trace(go.Pie(labels=df["Tecnología"], values=df["Ingresos 2014"],
77
+ name="Ingresos 2014", marker=dict(colors=colors), scalegroup='one'), row=1, col=1)
78
+
79
+ # Gráfico de Pie para Ingresos 2024 con tamaño proporcional
80
+ fig.add_trace(go.Pie(labels=df["Tecnología"], values=df["Ingresos 2024"],
81
+ name="Ingresos 2024", marker=dict(colors=colors), scalegroup='one'), row=1, col=2)
82
+
83
+ fig.update_layout(
84
+ font=dict(color='#ffffff', size=16),
85
+ paper_bgcolor='rgba(0,0,0,0)',
86
+ height=600,
87
+ annotations=[dict(text='2014', x=0.22, y=1.0, font_size=24, showarrow=False),
88
+ dict(text='2024', x=0.77, y=0.85, font_size=24, showarrow=False),
89
+ ])
90
+
91
+ return fig
92
+
93
+ # ESTA FUNCION CREA LAS GRAFICAS 6 y 7 del Tab 2
94
+
95
+
96
+ def crear_graf_df(columns: list, names: list, colors: list, y_title: str, df: pl.DataFrame) -> px.line:
97
+ """crear_graf_df: recibe de un mismo Dataframe la inf necesaria para graficar la tendencia de varias
98
+ columnas
99
+
100
+ Args:
101
+ columns (list): Lista con los nombres de las columnas a Graficar
102
+ names (list): Lista con los nombres de Cada Linea en el Gráfico
103
+ colors (list): Lista con los colores usar en el Gráfico
104
+ y_title (str): Titulo del eje y
105
+ df (pl.DataFrame): Dataframe del cual se sacarán los datos a graficar
106
+
107
+ Returns:
108
+ px.line: Grafico tipo linea de la libreria plotly
109
+ """
110
+
111
+ fig = px.line()
112
+ for i in range(3):
113
+ fig.add_scatter(x=df['fecha'], y=df[columns[i]],
114
+ name=names[i], mode='lines', line=dict(color=colors[i]))
115
+ fig.update_layout(
116
+ xaxis_title='Periodo',
117
+ yaxis_title=y_title,
118
+ font=dict(color='#ffffff', size=16),
119
+ paper_bgcolor='rgba(0,0,0,0)',
120
+ plot_bgcolor='rgba(0,0,0,0)', # Fondo de la grilla transparente
121
+ xaxis=dict(showgrid=False, zeroline=True, linecolor='#ffffff'),
122
+ yaxis=dict(showgrid=False, zeroline=True, linecolor='#ffffff'),
123
+ height=580,
124
+ margin=dict(l=100, r=0, t=0, b=0)
125
+ )
126
+
127
+ return fig
128
+
129
+
130
+ # ESTA FUNCION CREA LA TABLA DE LA DIAPOSITIVA 8 DEL CONTEXTO
131
+ def crear_tabla(df: pl.DataFrame) -> go.Figure:
132
+ """crear_tabla: Crea la tabla donde se comparan las Variaciones de Ingresos
133
+ y accesos de las distintas tecnologías en el 04_eda_comparando_tecnologias.ipynb
134
+
135
+ Args:
136
+ df (pl.DataFrame): Dataframe con la información a mostrar en la tabla
137
+
138
+ Returns:
139
+ go.Fig: Tabla de la Libreria Plotly
140
+ """
141
+ df = df.with_columns([
142
+ ((pl.col('Accesos 2024') / pl.col('Accesos 2014')) - 1).alias('Variación Accesos'),
143
+ ((pl.col('Ingresos 2024') / pl.col('Ingresos 2014')) - 1).alias('Variación Ingresos')
144
+ ])
145
+ lista_varia_accesos = []
146
+ lista_varia_ingresos = []
147
+ for i in range(4):
148
+ lista_varia_accesos.append(str(round((df[i, 5] * 100), 2)) + ' %')
149
+ lista_varia_ingresos.append(str(round((df[i, 6] * 100), 2)) + ' %')
150
+
151
+ header = dict(values=['Tecnología', 'Variación Accesos', 'Variación Ingresos'],
152
+ fill_color='lavender',
153
+ align='center')
154
+
155
+ cells = dict(values=[
156
+ ['Internet', 'Telefonía Móvil', 'Telefonía Fija', 'Televisión'],
157
+ lista_varia_accesos,
158
+ lista_varia_ingresos
159
+ ],
160
+ fill_color=[['#22D3EE', '#38C172', '#F6993F', '#FFED4A'], # Colores personalizados para cada fila
161
+ ['#22D3EE', '#38C172', '#F6993F', '#FFED4A'], # Colores de fondo para Variación Accesos
162
+ ['#22D3EE', '#38C172', '#F6993F', '#FFED4A']], # Colores de fondo para Variación Ingresos
163
+ align=['left', 'center', 'center'],
164
+ height=30,
165
+ )
166
+
167
+ fig = go.Figure(data=[go.Table(header=header, cells=cells, columnwidth=[300, 300, 300],)])
168
+
169
+ # Ajustar el layout para que se ajuste al tamaño de la tabla
170
+ fig.update_layout(
171
+ font=dict(color='black', size=18),
172
+ paper_bgcolor='rgba(0,0,0,0)',
173
+ width=800,
174
+ height=600,
175
+ margin=dict(l=300, r=0, t=170, b=0)
176
+ )
177
+
178
+ # Retorna la tabla
179
+ return fig
180
+
181
+
182
+ # FUNCION QUE DEVUELVE LAS GRAFICAS DE LAS DIAPOSITIVAS 9 Y 10
183
+ def crea_graficas_9_10(df: pl.DataFrame, num_diapositiva: int) -> px.line:
184
+ """Se encarga de Graficar las Diapositivas 9 y 10 de la Tab2 "¿Porqué Internet?
185
+
186
+ Args:
187
+ df (pl.DataFrame): Dataframe con los Datos a Graficar
188
+ num_diapositiva (int): Numero de la Diapositiva a representar
189
+
190
+ Returns:
191
+ px.Line: Grafico de Lineas de Tendencias de Rangos de Velocidad o Tecnologias (según
192
+ sea el parámetro num_diapositiva recibido) de la libreria Plotly Express
193
+ """
194
+ if num_diapositiva == 9:
195
+ columns = ['ADSL', 'CABLEMODEM', 'FIBRA', 'WIRELESS']
196
+ colors = ['#FFA15A', '#19D3F3', '#FF6692', '#B6E880']
197
+ else:
198
+ colors = ['#636EFA', '#EF553B', '#00CC96', '#AB63FA']
199
+ columns = ['Hasta 10 Mbps', '10.01 - 30 Mbps', '30.01 - 100 Mbps', 'Mayor a 100 Mbps']
200
+ names = columns
201
+
202
+ fig = px.line()
203
+ for i in range(len(columns)):
204
+ fig.add_scatter(x=df['Fecha'], y=df[columns[i]],
205
+ name=names[i], mode='lines', line=dict(color=colors[i]))
206
+ fig.update_layout(
207
+ xaxis_title='Periodo',
208
+ yaxis_title='Cantidad de Accesos',
209
+ font=dict(color='#ffffff', size=16),
210
+ paper_bgcolor='rgba(0,0,0,0)',
211
+ plot_bgcolor='rgba(0,0,0,0)', # Fondo de la grilla transparente
212
+ xaxis=dict(showgrid=False, zeroline=True, linecolor='#ffffff'),
213
+ yaxis=dict(showgrid=False, zeroline=True, linecolor='#ffffff'),
214
+ # width=800,
215
+ height=580,
216
+ margin=dict(l=100, r=0, t=0, b=0)
217
+ )
218
+ return fig
219
+
220
+
221
+ def retorna_grafico_tab2(numero_graf: int) -> html.Div:
222
+ """retorna_grafico_tab2: Según sea el numero de grafico solicitado se apoya en las funciones
223
+ que se encuentran en este mismo archivo para solicitarles la grafica,
224
+ y encapsularla dentro de un dcc.Graph que va a ser contenido en un
225
+ contenedor html.Div.
226
+ Hablamos de los Graficos de la Pestaña o Tab 2 "¿Porqué Internet?
227
+
228
+ Args:
229
+ numero_graf (int): Numero de grafico solicitado
230
+
231
+ Returns:
232
+ html.Div: Componente con el Grafico a Devolver
233
+ """
234
+ if numero_graf in [1, 2, 4]:
235
+ if numero_graf == 1:
236
+ fig = crear_grafica(df_list=dfs_4, y_column='ingresos_miles',
237
+ list_names=list_4, colors=colors_4)
238
+ elif numero_graf == 2:
239
+ fig = crear_grafica(df_list=dfs_4, y_column='ingresos_dolar_miles',
240
+ list_names=list_4, colors=colors_4)
241
+ else:
242
+ fig = crear_grafica(df_list=dfs_3, y_column='accesos_100_hab',
243
+ list_names=list_3, colors=colors_3)
244
+ elif numero_graf == 3:
245
+ fig = fig = crear_graf_pie(df=df_pies, colors=colors_4)
246
+ elif numero_graf in [5, 6, 7]:
247
+ if numero_graf == 5:
248
+ columns = ['total_accesos_post', 'total_accesos_pre', 'total_accesos']
249
+ names = ['Accesos Post-Pagos', 'Accesos Pre-Pagos', 'Total Accesos']
250
+ y_title = 'Accesos'
251
+ elif numero_graf == 6:
252
+ columns = ['llamadas_post_miles', 'llamadas_pre_miles', 'total_llamadas']
253
+ names = ['Llamadas Post-Pagos (miles)', 'Llamadas Pre-Pagos (miles)', 'Total Llamadas (miles)']
254
+ y_title = 'Llamadas'
255
+ else:
256
+ columns = ['minutos_post_miles', 'minutos_pre_miles', 'total_minutos']
257
+ names = ['Minutos Post-Pagos (miles)', 'Minutos Pre-Pagos (miles)', 'Total Minutos (miles)']
258
+ y_title = 'Minutos'
259
+ colors = ['#9fbc12', ' #045426 ', '#38C172']
260
+ fig = crear_graf_df(columns=columns, names=names, colors=colors,
261
+ y_title=y_title, df=telefonia_movil)
262
+ elif numero_graf == 8:
263
+ fig = crear_tabla(df=df_pies)
264
+ elif numero_graf == 9:
265
+ fig = crea_graficas_9_10(df=tecnologias_grafico_9.sort('Fecha'), num_diapositiva=9)
266
+ elif numero_graf == 10:
267
+ fig = crea_graficas_9_10(df=rangos_grafico_10.sort('Fecha'), num_diapositiva=10)
268
+
269
+ config = {'displayModeBar': False}
270
+
271
+ componente_graf_tab4 = html.Div([
272
+ dcc.Graph(figure=fig, config=config)
273
+ ])
274
+ return componente_graf_tab4
components/component_tab2_left.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dash import html
2
+ import dash_daq as daq
3
+
4
+ component_tab2_left = html.Div([
5
+ html.Div(html.Label("Tendencias Tecnologías"), className='title_left'),
6
+ html.Br(),
7
+ html.Br(),
8
+ html.Div([
9
+ html.Label("Diapositiva Número "),
10
+ daq.NumericInput(
11
+ id='control_slides_tab2',
12
+ value=0,
13
+ min=0,
14
+ max=10,
15
+ size=60,
16
+ style={'backgroundColor': '#f0f0f0'} # Cambia el color de fondo aquí
17
+ ),
18
+ ], id='container_control_slides'),
19
+ html.Br(),
20
+ html.Br(),
21
+ html.Br(),
22
+ html.Br(),
23
+ html.Div(id='texto_tab2')
24
+ ])
components/component_tab2_textos.py ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dash import html
2
+
3
+ componente_1 = html.Div([
4
+ html.Div(html.Label('Importante Analizar'), className='title_left'),
5
+ html.Br(),
6
+ html.Div([
7
+ html.P([
8
+ 'Desde el Año ',
9
+ html.B('2018'),
10
+ ' al ',
11
+ html.B('2024'),
12
+ ' se observa un aumento superior a ',
13
+ html.B('1000 %'),
14
+ ' !!!'
15
+ ], style={
16
+ 'text-indent': '1.5rem', # Sangría del párrafo
17
+ 'line-height': '1.6', # Espacio de interlineado
18
+ 'text-align': 'justify', # Justificado
19
+ 'font-size': '1.1rem' # Tamaño de la letra
20
+ })
21
+ ], className='parrafo_left')
22
+ ])
23
+
24
+ componente_2 = html.Div([
25
+ html.Div(html.Label('Analizando lo Observado'), className='title_left'),
26
+ html.Br(),
27
+ html.Div([
28
+ html.P([
29
+ 'Escenario de Inflación y/o Devaluación Local',
30
+ ], style={
31
+ 'text-indent': '1.5rem', # Sangría del párrafo
32
+ 'line-height': '1.6', # Espacio de interlineado
33
+ 'text-align': 'justify', # Justificado
34
+ 'font-size': '1.1rem' # Tamaño de la letra
35
+ })
36
+ ], className='parrafo_left')
37
+ ])
38
+
39
+ componente_3 = html.Div([
40
+ html.Div(html.Label('Analizando lo Observado'), className='title_left'),
41
+ html.Br(),
42
+ html.Div([
43
+ html.P([
44
+ 'Ingresos de 2024 representan ',
45
+ html.B('48.79 %'),
46
+ ' con respecto a 2014'
47
+ ], style={
48
+ 'text-indent': '1.5rem', # Sangría del párrafo
49
+ 'line-height': '1.6', # Espacio de interlineado
50
+ 'text-align': 'justify', # Justificado
51
+ 'font-size': '1.1rem' # Tamaño de la letra
52
+ })
53
+ ], className='parrafo_left')
54
+ ])
55
+
56
+ componente_4 = html.Div([
57
+ html.Div(html.Label('Analizando lo Observado'), className='title_left'),
58
+ html.Br(),
59
+ html.Div([
60
+ html.P([
61
+ 'Claramente Internet es la única Tecnología que aumento su ',
62
+ 'penetración de Mercado'
63
+ ], style={
64
+ 'text-indent': '1.5rem', # Sangría del párrafo
65
+ 'line-height': '1.6', # Espacio de interlineado
66
+ 'text-align': 'justify', # Justificado
67
+ 'font-size': '1.1rem' # Tamaño de la letra
68
+ })
69
+ ], className='parrafo_left')
70
+ ])
71
+
72
+ componente_7 = html.Div([
73
+ html.Div(html.Label('Analizando lo Observado'), className='title_left'),
74
+ html.Br(),
75
+ html.Div([
76
+ html.P([
77
+ 'A pesar de la caida de minutos consumidos y llamadas realizadas los ',
78
+ 'accesos a la Telefonía Móvil han variado MUY POCO'
79
+ ], style={
80
+ 'text-indent': '1.5rem', # Sangría del párrafo
81
+ 'line-height': '1.6', # Espacio de interlineado
82
+ 'text-align': 'justify', # Justificado
83
+ 'font-size': '1.1rem' # Tamaño de la letra
84
+ })
85
+ ], className='parrafo_left')
86
+ ])
87
+
88
+
89
+ componente_8 = html.Div([
90
+ html.Div(html.Label('Queda Muy Claro !!!'), className='title_left'),
91
+ html.Br(),
92
+ html.Div([
93
+ html.P([
94
+ 'EL Internet es la Tecnología de Telecomunicaciones con mayor avance ',
95
+ 'de penetración en la última Decada'
96
+ ], style={
97
+ 'text-indent': '1.5rem', # Sangría del párrafo
98
+ 'line-height': '1.6', # Espacio de interlineado
99
+ 'text-align': 'justify', # Justificado
100
+ 'font-size': '1.1rem' # Tamaño de la letra
101
+ })
102
+ ], className='parrafo_left')
103
+ ])
104
+
105
+ componente_9 = html.Div([
106
+ html.Div(html.Label('A tener en Cuenta !!!'), className='title_left'),
107
+ html.Br(),
108
+ html.Div([
109
+ html.P([
110
+ 'A pesar de que los Accesos a Internet han venido creciendo con el tiempo ',
111
+ 'se observan tipos de tecnologías para acceder a ella, que vienen en declive'
112
+ ], style={
113
+ 'text-indent': '1.5rem', # Sangría del párrafo
114
+ 'line-height': '1.6', # Espacio de interlineado
115
+ 'text-align': 'justify', # Justificado
116
+ 'font-size': '1.1rem' # Tamaño de la letra
117
+ })
118
+ ], className='parrafo_left')
119
+ ])
120
+
121
+
122
+ componente_10 = html.Div([
123
+ html.Div(html.Label('Acá puede haber una Oportunidad'), className='title_left'),
124
+ html.Br(),
125
+ html.Div([
126
+ html.P([
127
+ 'Es claro que la población desea migrar a servicios de Internet, que les ofrezcan ',
128
+ 'una conexión de mayor velocidad, por eso la migración hacia FIBRA OPTICA y CABLEMODEM, ',
129
+ 'en deprimento de ADSL y WIFI'
130
+ ], style={
131
+ 'text-indent': '1.5rem', # Sangría del párrafo
132
+ 'line-height': '1.6', # Espacio de interlineado
133
+ 'text-align': 'justify', # Justificado
134
+ 'font-size': '1.1rem' # Tamaño de la letra
135
+ }),
136
+ html.Br(),
137
+ html.P([
138
+ 'PEEERO y en aquellas Localidades donde la Densidad de Población No Justifique un Cableado ??? ',
139
+ ], style={
140
+ 'text-indent': '1.5rem', # Sangría del párrafo
141
+ 'line-height': '1.6', # Espacio de interlineado
142
+ 'text-align': 'justify', # Justificado
143
+ 'font-size': '1.1rem' # Tamaño de la letra
144
+ }),
145
+ ], className='parrafo_left')
146
+ ])
147
+
148
+
149
+ textos_left_tab2 = [
150
+ componente_1,
151
+ componente_2,
152
+ componente_3,
153
+ componente_4,
154
+ None,
155
+ None,
156
+ componente_7,
157
+ componente_8,
158
+ componente_9,
159
+ componente_10
160
+ ]
components/component_tab3.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dash import html
2
+ from components.component_tab3_drop import retorna_tab3_drop
3
+
4
+
5
+ def retorna_tab3(periodos: list) -> html.Div:
6
+ """retorna_tab3: Componente que encapsula Todo el Tablero de la Visualización
7
+
8
+ Args:
9
+ periodos (list): Lista de periodos a mostrar en el Drop
10
+
11
+ Returns:
12
+ html.Div: Contenedor General del Tablero
13
+ """
14
+ component_tab_3 = html.Div([
15
+ # html.Div([retorna_tab3_left(periodos=periodos)], className='tab_subcontainers', id='tab3_left'),
16
+ html.Div([
17
+ html.Div([
18
+ html.Div([retorna_tab3_drop(periodos=periodos)], className='tab_subcontainers', id='drop_tab3'),
19
+ html.Div([], className='tab_subcontainers', id='tarjeta_1'),
20
+ html.Div([], className='tab_subcontainers', id='tarjeta_2'),
21
+ html.Div([], className='tab_subcontainers', id='tarjeta_3'),
22
+ ], id='zona_tarjeta_tab3'),
23
+ html.Div([
24
+ html.Div([
25
+ html.Div([], className='tab_subcontainers', id='barras_tab3'),
26
+ ], id='zona_barras_tab3'),
27
+ html.Div([
28
+ html.Div([], className='tab_subcontainers', id='pies_tab3'),
29
+ ], id='zona_pies_tab3')
30
+
31
+ ], id='zona_grafica_tab3')
32
+ ], id='tab3_right')
33
+ ], className='work_container', id='tab3_component')
34
+ return component_tab_3
components/component_tab3_barras.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import plotly.express as px
2
+ from dash import dcc, html
3
+ import polars as pl
4
+ import pandas as pd
5
+
6
+
7
+ def retorna_barras_tab3(df: pl.DataFrame) -> html.Div:
8
+ """retorna_barras_tab3: Retorna el Grafico de Barras que se muestra en el Tablero
9
+
10
+ Args:
11
+ df (pl.DataFrame): Dataframe con los datos necesarios para realizar el Gráfico
12
+
13
+ Returns:
14
+ html.Div: Contenedor con el Grafico de Barras
15
+ """
16
+ df = df.to_pandas()
17
+
18
+ df_grouped = df.melt(id_vars='Provincia',
19
+ value_vars=['Accesos 100 Hog', 'MBPS Media Bajada'],
20
+ var_name='Metrica',
21
+ value_name='Valor')
22
+
23
+ df_grouped = pd.merge(df_grouped, df[['Provincia', 'Accesos 100 Hog Anterior', 'KPI 100 Hog',
24
+ 'Cumplimineto KPI 100 Hog', 'Crecimiento Trimestral Accesos 100 Hog',
25
+ 'MBPS Anterior', 'KPI MBPS', 'Cumplimineto KPI MBPS',
26
+ 'Crecimiento Trimestral MBPS', 'Accesos 100 Hog', 'MBPS Media Bajada']],
27
+ on='Provincia', how='left')
28
+
29
+ fig = px.bar(df_grouped, x='Provincia', y='Valor', color='Metrica', barmode='group',
30
+ custom_data=df_grouped)
31
+
32
+ fig.update_traces(
33
+ hovertemplate="<br>".join([
34
+ "<b>Provincia: %{customdata[0]}</b>",
35
+ "Accesos 100 Hog del Trimestre: %{customdata[11]}",
36
+ "MBPS del Trimestre: %{customdata[12]}",
37
+ "</br>"
38
+ "<b>KPI Accesos 100 Hog: Crecimiento Trimestral 2%</b>",
39
+ "Valor Anterior: %{customdata[3]}",
40
+ "<b>Objetivo KPI: %{customdata[4]}</b>",
41
+ "<b>Cumplimiento KPI: %{customdata[5]} %</b>",
42
+ "Crecimiento Trimestral: %{customdata[6]} %",
43
+ "<br>"
44
+ "<b>KPI MBPS: Crecimiento Trimestral 5%</b>",
45
+ "Valor Anterior: %{customdata[7]}",
46
+ "<b>Objetivo KPI: %{customdata[8]}</b>",
47
+ "<b>Cumplimiento KPI: %{customdata[9]} % </b>",
48
+ "Crecimiento Trimestral: %{customdata[10]} %",
49
+ ]),
50
+ hoverlabel=dict(bgcolor="white", font_color="black", font_size=16),
51
+ width=0.4,
52
+ )
53
+
54
+ fig.update_layout(
55
+ xaxis_title="",
56
+ yaxis_title="Accesos",
57
+ font=dict(color='#ffffff', size=14),
58
+ plot_bgcolor='rgba(0,0,0,0)',
59
+ paper_bgcolor='rgba(0,0,0,0)',
60
+ xaxis=dict(showgrid=False, zeroline=True, linecolor='#ffffff', tickangle=-90),
61
+ yaxis=dict(showgrid=False, zeroline=True, linecolor='#ffffff'),
62
+ legend=dict(
63
+ x=0.8,
64
+ y=1.1,
65
+ orientation='v'
66
+ )
67
+ )
68
+ componente = html.Div([
69
+ html.Label("Accesos a Internet por cada 100 Hogares y Velocidad Media de Bajada", className='title_left'),
70
+ html.Br(),
71
+ dcc.Graph(figure=fig, config={'displayModeBar': False}),
72
+ html.Label("Nota: Los KPIs por PROVINCIA se muestran en los ToolTips", id='pie_pagina_tab3')
73
+ ], style={'width': '100%', 'height': '80%'}, id='grafico_barras_tab3')
74
+ return componente
components/component_tab3_donuts.py ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import polars as pl
2
+ import plotly.graph_objects as go
3
+ from dash import html, dcc
4
+
5
+
6
+ def retorna_pies_tab3(df: pl.DataFrame) -> html.Div:
7
+ """retorna_pies_tab3: Retorna los Graficos tipo torta del Tablero
8
+
9
+ Args:
10
+ df (pl.DataFrame): Dataframe con la data para generar los gráficos
11
+
12
+ Returns:
13
+ html.Div: Contenedor con los Gráficos tipo barra
14
+ """
15
+ valores_pie_rangos = [df['Hasta 10 Mbps'].sum(), df['10.01 - 30 Mbps'].sum(),
16
+ df['30.01 - 100 Mbps'].sum(), df['Mayor a 100 Mbps'].sum()]
17
+ valores_tecnologias = [df['ADSL'].sum(), df['CABLEMODEM'].sum(), df['FIBRA'].sum(), df['WIRELESS'].sum()]
18
+
19
+ # Crear gráfico Donut para rangos
20
+ fig_rangos = go.Figure(go.Pie(
21
+ labels=['Hasta 10 Mbps', '10.01 - 30 Mbps', '30.01 - 100 Mbps', 'Mayor a 100 Mbps'],
22
+ values=valores_pie_rangos,
23
+ marker=dict(colors=['#636EFA', '#EF553B', '#00CC96', '#AB63FA']),
24
+ legendgroup='rangos',
25
+ hoverlabel=dict(
26
+ font_size=16,
27
+ font_color="black",
28
+ )
29
+ ))
30
+
31
+ fig_rangos.update_layout(
32
+ font=dict(color='#ffffff', size=14),
33
+ paper_bgcolor='rgba(0,0,0,0)',
34
+ height=230,
35
+ margin=dict(t=20, b=0, l=0, r=20),
36
+ legend=dict(
37
+ title="Rangos",
38
+ yanchor="top",
39
+ y=0.9,
40
+ xanchor="left",
41
+ x=1.0,
42
+ traceorder='normal'
43
+ )
44
+ )
45
+
46
+ # Crear gráfico Donut para tecnologias
47
+ fig_tecnologias = go.Figure(go.Pie(
48
+ labels=['ADSL', 'CABLEMODEM', 'FIBRA', 'WIRELESS'],
49
+ values=valores_tecnologias,
50
+ marker=dict(colors=['#FFA15A', '#19D3F3', '#FF6692', '#B6E880']),
51
+ legendgroup='tecnologias',
52
+ hoverlabel=dict(
53
+ font_size=16,
54
+ font_color="black",
55
+ )
56
+ ))
57
+
58
+ fig_tecnologias.update_layout(
59
+ font=dict(color='#ffffff', size=14),
60
+ paper_bgcolor='rgba(0,0,0,0)',
61
+ height=230,
62
+ margin=dict(t=0, b=0, l=0, r=20),
63
+ legend=dict(
64
+ title="Tecnologías",
65
+ yanchor="top",
66
+ y=0.9,
67
+ xanchor="left",
68
+ x=1.0,
69
+ traceorder='normal'
70
+ )
71
+ )
72
+
73
+ config = {'displayModeBar': False}
74
+
75
+ # Crear los componentes dcc.Graph dentro de un html.Div
76
+ componente_graf_tab3 = html.Div([
77
+ html.Label("Accesos por Rangos de Velocidad y tecnologías", className='title_left'),
78
+ dcc.Graph(figure=fig_rangos, config=config),
79
+ html.Br(),
80
+ html.Br(),
81
+ dcc.Graph(figure=fig_tecnologias, config=config)
82
+ ])
83
+
84
+ return componente_graf_tab3
components/component_tab3_drop.py ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dash import html, dcc
2
+
3
+
4
+ def retorna_tab3_drop(periodos: list) -> html.Div:
5
+ """retorna_tab3_drop: Retorna el componente Drop del Tablero
6
+
7
+ Args:
8
+ periodos (list): Lista de Periodos a desplegar en el Drop
9
+
10
+ Returns:
11
+ html.Div: Contenedor con el componente Drop
12
+ """
13
+ component_drop = html.Div([
14
+ # html.Div(html.Label("Accesos Internet"), className='title_left'),
15
+ html.Div(html.Label("Selecciona el Periodo (Trim)"), className='title_left'),
16
+ html.Br(),
17
+ html.Div([
18
+ # html.Div(html.Label("Periodo"), id='label_periodo'),
19
+ dcc.Dropdown(
20
+ id="drop-tab3",
21
+ options=periodos,
22
+ value=periodos[0],
23
+ style={
24
+ "backgroundColor": "#ffffff",
25
+ "fontSize": 18,
26
+ "color": "rgb(51, 51, 51)",
27
+ "border-radius": "1vh",
28
+ },
29
+ ),
30
+ ], className='one_drop_tab4'),
31
+
32
+ ], className='tab_left')
33
+ return component_drop
components/component_tab3_tarjetas.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dash import html
2
+ import polars as pl
3
+
4
+
5
+ def retorna_tarjetas_tab3(df: pl.DataFrame, accesos: int) -> tuple[html.Div, html.Div, html.Div]:
6
+ """retorna_tarjetas_tab3: Retorna las 3 tarjetas del Tablero de la visualización
7
+
8
+ Args:
9
+ df (pl.DataFrame): Dataframe con la información de las primeras 2 tarjetas
10
+ accesos (int): Información a Colocar en la Tercera Tarjeta
11
+
12
+ Returns:
13
+ tuple[html.Div, html.Div, html.Div]:
14
+ html.Div: Tarjeta que muestra "Variacion Trimestral Acc 100 Hog"
15
+ html.Div: Tarjeta que muestra "Variacion Trimestral MBPS"
16
+ html.Div: Tarjeta que muestra "Total Accesos Trimestre"
17
+ """
18
+ tarjeta_1 = html.Div([
19
+ html.Div(html.Label('Variación Trimestral Acc 100 Hog'), className='title_left'),
20
+ html.Br(),
21
+ html.Div(html.Label(f'{df["Crecimiento Accesos 100 Hog"][0]} %'), className='tarjetas')
22
+ ], className='contenedor_tarjetas')
23
+
24
+ tarjeta_2 = html.Div([
25
+ html.Div(html.Label('Variación Trimestral MBPS'), className='title_left'),
26
+ html.Br(),
27
+ html.Div(html.Label(f'{df["Crecimineto MBPS Media Bajada"][0]} %'), className='tarjetas')
28
+ ], className='contenedor_tarjetas')
29
+
30
+ tarjeta_3 = html.Div([
31
+ html.Div(html.Label('Total Accesos en Trimestre'), className='title_left'),
32
+ html.Br(),
33
+ html.Div(html.Label(f'{accesos:,}'), className='tarjetas')
34
+ ], className='contenedor_tarjetas')
35
+
36
+ return (tarjeta_1, tarjeta_2, tarjeta_3)
components/component_tab4.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dash import html
2
+ import plotly.express as px
3
+ import polars as pl
4
+ from components.component_tab4_left import component_tab4_left
5
+
6
+
7
+ df_accesos_localidades = pl.read_parquet('data/accesos_localidades_dash.parquet')
8
+
9
+
10
+ component_tab_4 = html.Div([
11
+ html.Div([component_tab4_left], className='tab_subcontainers', id='tab4_left'),
12
+ html.Div([], className='tab_subcontainers', id='tab4_center'),
13
+ html.Div([], className='tab_subcontainers', id='tab4_right')
14
+ ], className='work_container' , id='tab4_component')
components/component_tab4_donuts.py ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import polars as pl
2
+ import plotly.graph_objects as go
3
+ from dash import html, dcc
4
+
5
+
6
+ def retorna_graf_tab4(df_pie_rangos: pl.DataFrame, df_tecnologias: pl.DataFrame) -> html.Div:
7
+ """retorna_graf_tab4: Retorna el contenedor que contiene los Gráficos tipo Tortas de la pestaña
8
+ que muestra el Mapa en la visualizació
9
+ Args:
10
+ df_pie_rangos (pl.DataFrame): Dataframe con la data para el gráfico de Rangos de Velocidades
11
+ df_tecnologias (pl.DataFrame): Dataframe con la data pata el gráfico de las tecnologías
12
+
13
+ Returns:
14
+ html.Div: contenedor con los gráficos tipo torta
15
+ """
16
+ # Convertir columnas a listas de valores
17
+ valores_pie_rangos = [df_pie_rangos[0, i] for i in range(len(df_pie_rangos.columns))]
18
+ valores_tecnologias = [df_tecnologias[0, i] for i in range(len(df_tecnologias.columns))]
19
+
20
+ # Crear gráfico Donut para df_pie_rangos
21
+ fig_rangos = go.Figure(go.Pie(
22
+ labels=df_pie_rangos.columns,
23
+ values=valores_pie_rangos,
24
+ marker=dict(colors=['#636EFA', '#EF553B', '#00CC96', '#AB63FA']),
25
+ legendgroup='rangos',
26
+ hoverlabel=dict(
27
+ font_size=16,
28
+ font_color="black",
29
+ )
30
+ ))
31
+
32
+ fig_rangos.update_layout(
33
+ font=dict(color='#ffffff', size=16),
34
+ paper_bgcolor='rgba(0,0,0,0)',
35
+ height=270,
36
+ margin=dict(t=0, b=0, l=0, r=0),
37
+ legend=dict(
38
+ title='Rangos',
39
+ yanchor="top",
40
+ y=0.7,
41
+ xanchor="left",
42
+ x=0.9,
43
+ traceorder='normal'
44
+ )
45
+ )
46
+
47
+ # Crear gráfico Donut para df_tecnologias
48
+ fig_tecnologias = go.Figure(go.Pie(
49
+ labels=df_tecnologias.columns,
50
+ values=valores_tecnologias,
51
+ marker=dict(colors=['#FFA15A', '#19D3F3', '#FF6692', '#B6E880']),
52
+ legendgroup='tecnologias',
53
+ hoverlabel=dict(
54
+ font_size=16,
55
+ font_color="black",
56
+ )
57
+ ))
58
+
59
+ fig_tecnologias.update_layout(
60
+ font=dict(color='#ffffff', size=16),
61
+ paper_bgcolor='rgba(0,0,0,0)',
62
+ height=270,
63
+ margin=dict(t=0, b=0, l=0, r=0),
64
+ legend=dict(
65
+ title="Tecnologías",
66
+ yanchor="top",
67
+ y=0.7,
68
+ xanchor="left",
69
+ x=1.0,
70
+ traceorder='normal'
71
+ )
72
+ )
73
+
74
+ config = {'displayModeBar': False}
75
+
76
+ # Crear los componentes dcc.Graph dentro de un html.Div
77
+ componente_graf_tab4 = html.Div([
78
+ html.Label("Accesos por Rangos de Velocidad y tecnologías", className='title_left'),
79
+ html.Br(),
80
+ html.Br(),
81
+ html.Br(),
82
+ dcc.Graph(figure=fig_rangos, config=config),
83
+ html.Br(),
84
+ dcc.Graph(figure=fig_tecnologias, config=config)
85
+ ], id='contenedor_pies_tab4')
86
+
87
+ return componente_graf_tab4
components/component_tab4_left.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dash import html, dcc
2
+
3
+
4
+ minimos = [2000, 5000, 10000, 20000, 50000, 100000, 500000]
5
+ maximos = [5000, 10000, 20000, 50000, 100000, 500000, 3000000]
6
+
7
+
8
+ component_tab4_left = html.Div([
9
+ dcc.Store(id="store_tab4", data={"btn_tab4": 0}),
10
+ html.Div(html.Label("Rango Habitantes"), className='title_left'),
11
+ html.Br(),
12
+ html.Div([
13
+ html.Label("Minimo"),
14
+ dcc.Dropdown(
15
+ id="drop-minimo_tab4",
16
+ options=minimos,
17
+ value=minimos[0],
18
+ style={
19
+ "backgroundColor": "#ffffff",
20
+ "fontSize": 14,
21
+ "color": "rgb(51, 51, 51)",
22
+ "border-radius": "1vh",
23
+ },
24
+ ),
25
+ ], className='one_drop_tab4'),
26
+ html.Br(),
27
+ html.Div([
28
+ html.Label("Máximo"),
29
+ dcc.Dropdown(
30
+ id="drop-maximo_tab4",
31
+ options=maximos,
32
+ value=maximos[0],
33
+ style={
34
+ # "backgroundColor": "#70cbff",
35
+ "backgroundColor": "#ffffff",
36
+ "fontSize": 14,
37
+ "color": "rgb(51, 51, 51)",
38
+ "border-radius": "1vh",
39
+ },
40
+ ),
41
+ ], className='one_drop_tab4'),
42
+ html.Br(),
43
+ html.Br(),
44
+ html.Div(
45
+ html.Button("Ok", className="btns", id="btn_tab4"),
46
+ className="btn-container",
47
+ id="btn_container_tab4",
48
+ ),
49
+ html.Br(),
50
+ html.Div([], id='tab4_rangos_response'),
51
+ html.Br(),
52
+ # html.Br(),
53
+ html.Div([], id='tab4_texto_resultados')
54
+ ], className='tab_left')
components/component_tab4_mapa.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dash import dcc
2
+ import plotly.express as px
3
+ import polars as pl
4
+ import pandas as pd
5
+
6
+
7
+ def retorna_mapa(df: pl.DataFrame) -> dcc.Graph:
8
+ """retorna_mapa: Retorna el componente del Mapa de la visualizacion
9
+
10
+ Args:
11
+ df (pl.DataFrame): Dataframe con la data necesaria para el mapa
12
+
13
+ Returns:
14
+ dcc.Graph: Componente Grafico que encapsula al mapa
15
+ """
16
+ df = df.to_pandas()
17
+
18
+ # rangos de la población
19
+ bins = [2000, 5000, 10000, 20000, 50000, 100000, 500000, 10000000]
20
+ labels = [
21
+ '2.000-5.000 Hab',
22
+ '5.001-10.000 Hab',
23
+ '10.001-20.000 Hab',
24
+ '20.001-50.000 Hab',
25
+ '50.001-100.000 Hab',
26
+ '100.001-500.000 Hab',
27
+ 'Más de 500.000 Hab'
28
+ ]
29
+ df['Rango'] = pd.cut(df['Población'], bins=bins, labels=labels)
30
+
31
+ # Ajustando para que todas las burbujas sean del mismo tamaño
32
+ size_map = {
33
+ '2.000-5.000 Hab': 0.01,
34
+ '5.001-10.000 Hab': 0.01,
35
+ '10.001-20.000 Hab': 0.01,
36
+ '20.001-50.000 Hab': 0.01,
37
+ '50.001-100.000 Hab': 0.01,
38
+ '100.001-500.000 Hab': 0.01,
39
+ 'Más de 500.000 Hab': 0.01,
40
+ }
41
+ # Estableciendo los colores por Region que sean Fijos (siempre los mismos)
42
+ color_map = {
43
+ '2.000-5.000 Hab': '#1f77b4',
44
+ '5.001-10.000 Hab': '#ff7f0e',
45
+ '10.001-20.000 Hab': '#2ca02c',
46
+ '20.001-50.000 Hab': '#d62728',
47
+ '50.001-100.000 Hab': '#9467bd',
48
+ '100.001-500.000 Hab': '#8c564b',
49
+ 'Más de 500.000 Hab': '#e377c2'
50
+ }
51
+ df['Size'] = df['Rango'].map(size_map)
52
+ df['Size'] = 0.01
53
+ df['Color'] = df['Rango'].map(color_map)
54
+
55
+ fig = px.scatter_mapbox(
56
+ df,
57
+ lat="Latitud",
58
+ lon="Longitud",
59
+ hover_name="Localidad",
60
+ hover_data={"Provincia": True, "Partido": True, "Población": True, "Accesos 100 Hab": True,
61
+ "Size": False, "Rango": False, "Latitud": False, "Longitud": False},
62
+ size="Size",
63
+ size_max=5,
64
+ color="Rango",
65
+ color_discrete_map=color_map,
66
+ category_orders={"Rango": labels},
67
+ zoom=3.5,
68
+ height=660
69
+ )
70
+
71
+ # Estilo del Mapa
72
+ fig.update_layout(mapbox_style="carto-darkmatter")
73
+ fig.update_layout(margin={"r": 0, "t": 0, "l": 0, "b": 0})
74
+ fig.update_layout(mapbox=dict(center=dict(lat=-38.4161, lon=-63.6167), zoom=3.5))
75
+
76
+ fig.update_layout(
77
+ legend=dict(
78
+ title="Rango de Población",
79
+ x=0.60,
80
+ y=0.08,
81
+ traceorder="normal",
82
+ font=dict(color="#ffffff"),
83
+ bgcolor='rgba(0,0,0,0)'
84
+ )
85
+ )
86
+
87
+ fig.update_layout(
88
+ hoverlabel=dict(
89
+ font_size=18,
90
+ font_color="white",
91
+ )
92
+ )
93
+
94
+ fig.update_layout(clickmode='event+select')
95
+
96
+ fig.update_layout(mapbox_zoom=3.5)
97
+ config = {'displayModeBar': False}
98
+ mapa = dcc.Graph(id='mapa', figure=fig, config=config)
99
+ return mapa
100
+
101
+
102
+ '''
103
+ “open-street-map”: El estilo Inicial SI CORRE
104
+ “carto-positron”: Un estilo claro y minimalista. SI CORRE
105
+ “carto-darkmatter”: Un estilo oscuro y minimalista. SI CORRE
106
+ “stamen-terrain”: Un estilo que resalta el terreno. NO CORRE
107
+ “stamen-toner”: Un estilo en blanco y negro con líneas claras. NO CORRE
108
+ “stamen-watercolor”: Un estilo artístico que parece pintado con acuarelas. NO CORRE
109
+ “basic”: Un estilo básico y limpio. NO CORRE
110
+ “streets”: Un estilo que resalta las calles. NO CORRE
111
+ “outdoors”: Un estilo que resalta las áreas al aire libre. NO CORRE
112
+ “light”: Un estilo claro.
113
+ “dark”: Un estilo oscuro. No corre
114
+ “satellite”: Un estilo de imagen satelital. NO CORRE
115
+ “satellite-streets”: Imagen satelital con calles resaltadas. NO CORRE
116
+
117
+
118
+
119
+ '''
components/component_tab4_retorna_texto.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dash import html
2
+
3
+
4
+ def retorna_tab4_texto_resultado(
5
+ total_poblacion: int, total_localidades: int, total_accesos: int
6
+ ) -> html.Div:
7
+ """retorna_tab4_texto_resultado: Retorna la informacion tipo texto que se muestra en la parte
8
+ izquierda en la pestaña del mapa
9
+
10
+ Args:
11
+ total_poblacion (int): Número de habitantes en el Rango de habitantes escogido
12
+ total_localidades (int): Número de localidades en el Rango de habitantes escogido
13
+ total_accesos (int): Número de accesos a internet en el Rango de habitantes escogido
14
+
15
+ Returns:
16
+ html.Div: Contenedor con la Información tipo texto mostrada en la pestaña del Mapa
17
+ """
18
+ accesos_100_hab = round(100 * (total_accesos / total_poblacion), 2)
19
+ component = html.Div([
20
+ html.Div(html.Label('Datos de Valor'), className='title_left'),
21
+ html.Br(),
22
+ html.Label('Localidades del Rango'),
23
+ html.Br(),
24
+ html.Label(f"{total_localidades:,}"),
25
+ html.Br(),
26
+ html.Br(),
27
+ html.Label('Población del Rango'),
28
+ html.Br(),
29
+ html.Label(f"{total_poblacion:,}"),
30
+ html.Br(),
31
+ html.Br(),
32
+ html.Label('Total Accesos en Rango'),
33
+ html.Br(),
34
+ html.Label(f"{total_accesos:,}"),
35
+ html.Br(),
36
+ html.Br(),
37
+ html.Label('Accesos Cada 100 Hab'),
38
+ html.Br(),
39
+ html.Label(accesos_100_hab)
40
+ ], id='texto_tab4')
41
+ return component
data/EDA_internet_rangos.parquet ADDED
Binary file (10.3 kB). View file
 
data/EDA_internet_tecnologias.parquet ADDED
Binary file (13.4 kB). View file
 
data/accesos_localidades_dash.parquet ADDED
Binary file (140 kB). View file
 
data/data_tablero_dashboard.parquet ADDED
Binary file (50.8 kB). View file
 
data/df_pie_tab2.parquet ADDED
Binary file (2.12 kB). View file
 
data/internet_tab2.parquet ADDED
Binary file (7.48 kB). View file
 
data/rangos_internet_graficos_tab2 copy.parquet ADDED
Binary file (2.59 kB). View file
 
data/rangos_internet_graficos_tab2.parquet ADDED
Binary file (2.59 kB). View file
 
data/rangos_localidades.parquet ADDED
Binary file (77.8 kB). View file
 
data/tarjetas.parquet ADDED
Binary file (6.57 kB). View file
 
data/tecnologias_internet_graficos_tab2 copy.parquet ADDED
Binary file (2.97 kB). View file
 
data/tecnologias_internet_graficos_tab2.parquet ADDED
Binary file (2.97 kB). View file
 
data/telefonia_fija_tab2.parquet ADDED
Binary file (8.9 kB). View file
 
data/telefonia_movil_tab2.parquet ADDED
Binary file (12.1 kB). View file
 
data/television_tab2.parquet ADDED
Binary file (12.3 kB). View file
 
main.py ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dash import Dash, dcc, html, Input, Output, callback, State
2
+ import polars as pl
3
+ from utils.retorna_dfs_grfaicos_tab4 import retorna_dfs_graficos_tab4
4
+ from components.component_home import component_home
5
+ from components.component_tab2 import component_tab_2
6
+ from components.component_tab2_textos import textos_left_tab2
7
+ from components.component_tab2_grafico import retorna_grafico_tab2
8
+ from components.component_tab3 import retorna_tab3
9
+ from components.component_tab3_tarjetas import retorna_tarjetas_tab3
10
+ from components.component_tab3_barras import retorna_barras_tab3
11
+ from components.component_tab3_donuts import retorna_pies_tab3
12
+ from components.component_tab4 import component_tab_4
13
+ from components.component_tab4_mapa import retorna_mapa
14
+ from components.component_tab4_donuts import retorna_graf_tab4
15
+ from components.component_tab4_retorna_texto import retorna_tab4_texto_resultado
16
+
17
+ accesos_localidades = pl.read_parquet('data/accesos_localidades_dash.parquet')
18
+ rangos_localidades = pl.read_parquet('data/rangos_localidades.parquet')
19
+ data_tablero = pl.read_parquet('data/data_tablero_dashboard.parquet')
20
+ tarjetas = pl.read_parquet('data/tarjetas.parquet')
21
+ lista_periodos = data_tablero['Periodo Tablero'].unique().to_list()
22
+ lista_periodos.sort()
23
+ lista_periodos = [item[7:] for item in lista_periodos]
24
+ periodos_dashboard = lista_periodos.copy()
25
+ periodos_dashboard.pop(0)
26
+
27
+
28
+ app = Dash(
29
+ __name__,
30
+ suppress_callback_exceptions=True,
31
+ title="Telecomunicaciones Argentina",
32
+ meta_tags=[{"name": "viewport", "content": "width=device-width, initial-scale=1"}],
33
+ )
34
+
35
+
36
+ tabs_styles = {"height": "2em", "marginLeft": "0.5em", "marginRight": "1.5em"}
37
+ tab_style = {
38
+ "border": "1px solid #656565",
39
+ "color": "#d0d0d0",
40
+ "backgroundColor": "#2b2b2b",
41
+ "padding": "0.5em",
42
+ "fontWeight": "bold",
43
+ "fontSize": "0.9em",
44
+ }
45
+
46
+ tab_selected_style = {
47
+ "borderTop": "1px solid #ffffff",
48
+ "borderLeft": "1px solid #656565",
49
+ "borderRight": "1px solid #656565",
50
+ "backgroundColor": "#2b2b2b",
51
+ "color": "#ffffff",
52
+ "padding": "0.5em",
53
+ "fontSize": "1.1em",
54
+ }
55
+
56
+ app.layout = html.Div(
57
+ [
58
+ dcc.Tabs(
59
+ id="tabs-inline",
60
+ value="tab-1",
61
+ children=[
62
+ dcc.Tab(
63
+ label="Home",
64
+ value="tab-1",
65
+ style=tab_style,
66
+ selected_style=tab_selected_style,
67
+ ),
68
+ dcc.Tab(
69
+ label="¿Porqué Internet?",
70
+ value="tab-2",
71
+ style=tab_style,
72
+ selected_style=tab_selected_style,
73
+ ),
74
+ dcc.Tab(
75
+ label="Seguimiento a Métricas",
76
+ value="tab-3",
77
+ style=tab_style,
78
+ selected_style=tab_selected_style,
79
+ ),
80
+ dcc.Tab(
81
+ label="Mapa de Oportunidades",
82
+ value="tab-4",
83
+ style=tab_style,
84
+ selected_style=tab_selected_style,
85
+ ),
86
+ ],
87
+ style=tabs_styles,
88
+ ),
89
+ html.Div(id="tabs-content-inline-3"),
90
+ ]
91
+ )
92
+
93
+
94
+ @callback(Output("tabs-content-inline-3", "children"), Input("tabs-inline", "value"))
95
+ def render_content(tab):
96
+ if tab == "tab-1":
97
+ return component_home
98
+ elif tab == "tab-2":
99
+ return component_tab_2
100
+ elif tab == "tab-3":
101
+ return retorna_tab3(periodos=periodos_dashboard)
102
+ elif tab == "tab-4":
103
+ return component_tab_4
104
+
105
+
106
+ @app.callback(
107
+ Output('tab4_rangos_response', 'children'),
108
+ Output('tab4_center', 'children'),
109
+ Output('tab4_right', 'children'),
110
+ Output('tab4_texto_resultados', 'children'),
111
+ Output("store_tab4", "data"),
112
+ Input('btn_tab4', 'n_clicks'),
113
+ Input('drop-minimo_tab4', 'value'),
114
+ Input('drop-maximo_tab4', 'value'),
115
+ State("store_tab4", "data"),
116
+ prevent_initial_call=True,
117
+ )
118
+ def update_tab_4(n_clicks: int, min_value: int, max_value: int, data: dict
119
+ ) -> tuple[html.Label | html.Br, html.Div | None , html.Div | None, html.Div | None, dict]:
120
+ """update_tab_4: Actualiza los componentes de La Pestaña 4 o "Mapa de Oportunidades"
121
+
122
+ Args:
123
+ n_clicks (int): Numero de Veces que se le ha dado click al boton del tab 4
124
+ min_value (int): Valor seleccionado por el Usuario, capturado por un componente dcc.Drop (mínimo población)
125
+ max_value (int): Valor seleccionado por el Usuario, capturado por un componente dcc.Drop (máximo población)
126
+ data (dict): Banco de Datos tipo dcc.Store. pertenece al componente con el id="store_tab4" en el archivo
127
+ component_tab4_left.py Utilizado para llevar un paralelo de cuantas veces an clickleado el boton
128
+
129
+ Returns:
130
+ tuple[html.Label|html.Br, html.Div|None , html.Div|None, html.Div|None, dict]:
131
+ html.Label|html.Br: Label cuando se selecciona mal un rango, Br cuando es correcto el rango
132
+ html.Div|None : Componente que tiene el Mapa de la Tab 4
133
+ html.Div|None: Componente que contiene los dos graficos tipo pies de la tab 4
134
+ html.Div|None: Componente de Texto que se muestra en la parte izquierda de la pestaña
135
+ Tab_4 donde se dice Numero de Localidades, cantidad de Hab, etc
136
+ dict: Banco de Datos dcc.Store con id="store_tab4"
137
+ """
138
+ btn_tab4 = data.get("btn_tab4")
139
+ if not n_clicks or n_clicks == btn_tab4:
140
+ return (html.Br(), None, None, None, data)
141
+ if n_clicks > btn_tab4:
142
+ btn_tab4 += 1
143
+ data["btn_tab4"] = btn_tab4
144
+ if max_value > min_value:
145
+ response = html.Br()
146
+ df_mapa, df_pie_rangos, df_tecnologias, n_accesos, n_localidades = retorna_dfs_graficos_tab4(
147
+ df_accesos_localidades=accesos_localidades,
148
+ df_rangos=rangos_localidades,
149
+ hab_minimo=min_value,
150
+ hab_maximo=max_value
151
+ )
152
+ poblacion_total_rango = df_mapa['Población'].sum()
153
+ componente_texto = retorna_tab4_texto_resultado(
154
+ total_poblacion=poblacion_total_rango,
155
+ total_localidades=n_localidades,
156
+ total_accesos=n_accesos
157
+ )
158
+ mapa = retorna_mapa(df=df_mapa)
159
+ graficos_tab4 = retorna_graf_tab4(
160
+ df_pie_rangos=df_pie_rangos,
161
+ df_tecnologias=df_tecnologias['ADSL', 'CABLEMODEM', 'FIBRA', 'WIRELESS']
162
+ )
163
+ else:
164
+ response = html.Label('Rango no Permitido !!!')
165
+ mapa = None
166
+ graficos_tab4 = None
167
+ componente_texto = None
168
+ return (response, mapa, graficos_tab4, componente_texto, data)
169
+
170
+
171
+ @callback(
172
+ Output('title_right_tab2', 'children'),
173
+ Output('grafico_right_tab2', 'children'),
174
+ Output('texto_tab2', 'children'),
175
+ Input('control_slides_tab2', 'value'),
176
+ prevent_initial_call=True,
177
+ )
178
+ def update_tab_2(value: int) -> tuple[str | None, html.Div | None, html.Div | None]:
179
+ """update_tab_2: Se encarga de actualizar los componentes de la pesataña Tab2 o "¿Porque Internet?
180
+
181
+ Args:
182
+ value (int): Valor que se recibe del componente daq.NumericInput del archivo
183
+ component_tab2_left.py
184
+
185
+ Returns:
186
+ tuple[str|None, html.Div|None, html.Div|None]:
187
+ str|None: Título de la Diapositiva en la Tab 2 o "¿Porque Internet?
188
+ html.Div|None: Diapositiva (Gráfico) en la Tab 2 o "¿Porque Internet?
189
+ html.Div|None: Texto que se muestra en la parte izquierda de la pantalla
190
+ en la Tab 2 o "¿Porque Internet?
191
+ """
192
+ titulos_diapositivas = [
193
+ 'Ingresos en Miles de Pesos Argentinos',
194
+ 'Ingresos en Miles de Dolares',
195
+ 'Comparación de Ingresos en Dolares por Tecnología',
196
+ 'Accesos por cada 100 Habitantes',
197
+ 'Accesos de Telefonía Movil',
198
+ 'Cantidad de Llamadas Telefonía Movil',
199
+ 'Cantidad de Minutos Consumidos Telefonía Movil',
200
+ 'Evolución en Accesos e Ingresos en la última Decada',
201
+ 'Evolución de los Accesos de las Tecnologías para el Acceso a Internet',
202
+ 'Evolución de los Accesos a Internet en los Distintos Rangos de Velocidad',
203
+ ]
204
+ if value in range(1, 11):
205
+ componente = retorna_grafico_tab2(numero_graf=value)
206
+ title = html.Label(titulos_diapositivas[value - 1])
207
+ texto = textos_left_tab2[value - 1] if value in [1, 2, 3, 4, 7, 8, 9, 10] else None
208
+ return (title, componente, texto)
209
+ else:
210
+ return (None, None, None)
211
+
212
+
213
+ @app.callback(
214
+ Output('tarjeta_1', 'children'),
215
+ Output('tarjeta_2', 'children'),
216
+ Output('tarjeta_3', 'children'),
217
+ Output('barras_tab3', 'children'),
218
+ Output('pies_tab3', 'children'),
219
+ Input('drop-tab3', 'value'),
220
+ )
221
+ def update_tab_3(value: str) -> tuple[html.Div, html.Div, html.Div, html.Div, html.Div]:
222
+ """update_tab_3: Se encarga de actualizar los componentes de la Tab 3 o "Seguimiento a Métricas"
223
+
224
+ Args:
225
+ value (str): Periodo Seleccionado por el Usuario en la Pestaña del Tablero
226
+
227
+ Returns:
228
+ tuple[html.Div, html.Div, html.Div, html.Div, html.Div]:
229
+ html.Div: Componente que se Ubica en la tarjeta Variacion Trimestral Accesos 100 Hog
230
+ html.Div: Componente que se Ubica en la tarjeta Variacion Trimestral MBPS
231
+ html.Div: Componente que se Ubica en la tarjeta Total Accesos en Trimestre
232
+ html.Div: Componente con el Grafico de Barras del Tablero
233
+ html.Div Componente con los dos Graficos tipo Pie del tablero
234
+ """
235
+ mask = data_tablero['Periodo'] == value
236
+ df = data_tablero.filter(mask)
237
+ barras = retorna_barras_tab3(df=df)
238
+ pies = retorna_pies_tab3(df=df)
239
+ mask = tarjetas['Periodo'] == value
240
+ df_tarjetas = tarjetas.filter(mask)
241
+ tarjeta_1, tarjeta_2, tarjeta_3 = retorna_tarjetas_tab3(df=df_tarjetas, accesos=df['Total Accesos'].sum())
242
+ return (tarjeta_1, tarjeta_2, tarjeta_3, barras, pies)
243
+
244
+
245
+ if __name__ == "__main__":
246
+ app.run(debug=False)
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ dash==2.16.1
2
+ dash_daq==0.5.0
3
+ pandas==2.2.2
4
+ plotly==5.21.0
5
+ polars==1.2.1
6
+ pyarrow==17.0.0
utils/retorna_dfs_grfaicos_tab4.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import polars as pl
2
+
3
+
4
+ def retorna_dfs_graficos_tab4(
5
+ df_accesos_localidades: pl.DataFrame,
6
+ df_rangos: pl.DataFrame,
7
+ hab_minimo: int,
8
+ hab_maximo: int) -> tuple[pl.DataFrame, pl.DataFrame, pl.DataFrame, int, int]:
9
+ """retorna_dfs_graficos_tab4: Es llamada desde la Callback que actualiza el TAB 4 o
10
+ 'Mapa de Oportunidades` en la visualización. Se encarga de preparar la
11
+ data para los distintos componentes de esa pestaña de la visualización
12
+
13
+ Args:
14
+ df_accesos_localidades (pl.DataFrame): Dataframe con la Data de todas las localidades
15
+ df_rangos (pl.DataFrame): Dataframe con la data de los Rangos de Velocidad asociados a las localidades
16
+ hab_minimo (int): Rango inferior de habitantes selecionado por el usuario
17
+ hab_maximo (int): Rango superior de Habitantes selecionado por el usuario
18
+
19
+ Returns:
20
+ tuple[pl.DataFrame,pl.DataFrame, pl.DataFrame, int, int]:
21
+ df_mapa: Dataframe con información de localidades seleccionadas con sus latitudes y longitudes
22
+ e informacion para el tooltip
23
+ df_pie_rangos: Dataframe que va dirigido a alimentar el Grafico de Pie de Rango de Velocidades
24
+ df_tecnologias: Dataframe que va dirigido a alimentar el Grafico de Pies de las Tecnologias
25
+ total_accesos: Dato que se muestra en la Seccion Izquierda de la pestaña, donde se muestra texto
26
+ total_localidades:Dato que se muestra en la Seccion Izquierda de la pestaña, donde se muestra texto
27
+
28
+
29
+
30
+ """
31
+ '''Obteniendo la Data que va para el Mapa, df_mapa'''
32
+ mask = (df_accesos_localidades['Población'] >= hab_minimo) &\
33
+ (df_accesos_localidades['Población'] <= hab_maximo)
34
+
35
+ # Esta lista de Localidades (en el rango de poblacion) la utilizaré para filtrar en el
36
+ # dataframe de rangos de velocidades
37
+ lista_ids_localidades = df_accesos_localidades.filter(mask)['id_localidad'].to_list()
38
+ total_localidades = len(lista_ids_localidades)
39
+
40
+ columns = ['Provincia', 'Partido', 'Localidad', 'Población', 'Accesos 100 Hab', 'Longitud', 'Latitud']
41
+ df_mapa = df_accesos_localidades.filter(mask)[columns]
42
+
43
+ '''Obteniendo la Data para el grafico que clasifica por tipo de Tecnologia'''
44
+ df_tecnologias = pl.DataFrame()
45
+ adsl = df_accesos_localidades.filter(mask)['ADSL'].sum()
46
+ cable_modem = df_accesos_localidades.filter(mask)['CABLEMODEM'].sum()
47
+ fibra = df_accesos_localidades.filter(mask)['FIBRA'].sum()
48
+ wireless = df_accesos_localidades.filter(mask)['WIRELESS'].sum()
49
+ satelital = df_accesos_localidades.filter(mask)['SATELITAL'].sum()
50
+ winmax = df_accesos_localidades.filter(mask)['WINMAX'].sum()
51
+ tecnologias = [adsl, cable_modem, fibra, wireless, satelital, winmax]
52
+ columns = ['ADSL', 'CABLEMODEM', 'FIBRA', 'WIRELESS', 'SATELITAL', 'WINMAX']
53
+ for i in range(6):
54
+ df_tecnologias = df_tecnologias.with_columns(pl.lit(tecnologias[i]).alias(columns[i]))
55
+
56
+ '''Obteniendo la Data que va para el Pie con Rangos de Velocidades, df_pie_rangos'''
57
+ df_pie_rangos = pl.DataFrame()
58
+ rangos = ['Hasta 10 Mbps', '10.01 - 30 Mbps', '30.01 - 100 Mbps', 'Mayor a 100 Mbps']
59
+ velocidades = [(0, 10), (10.01, 30), (30.01, 100), (100.01, 1000000)]
60
+
61
+ total_accesos = 0
62
+ for i in range(4):
63
+ menor = velocidades[i][0]
64
+ mayor = velocidades[i][1]
65
+ mask = (df_rangos['id_localidad'].is_in(lista_ids_localidades)) &\
66
+ (df_rangos['velocidad_mbps'].is_between(menor, mayor))
67
+ accesos = df_rangos.filter(mask)['accesos'].sum()
68
+ total_accesos += accesos
69
+ df_pie_rangos = df_pie_rangos.with_columns(pl.lit(accesos).alias(rangos[i]))
70
+
71
+ return (df_mapa, df_pie_rangos, df_tecnologias, total_accesos, total_localidades)