Razkaroth commited on
Commit
0c096c9
·
1 Parent(s): 88baf27

finishes explorer

Browse files
Files changed (3) hide show
  1. app-old.py +195 -0
  2. app.py +250 -144
  3. media/logo-poplab.png +0 -0
app-old.py ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import geopandas as gpd
4
+ from diagnostics import run_df_diagnostics
5
+ import plotly.express as px
6
+
7
+
8
+ st.set_page_config(
9
+ page_title="Explorador REPDA",
10
+ page_icon="🧊",
11
+ layout="wide",
12
+ )
13
+
14
+ st.title("Explorador REPDA")
15
+
16
+
17
+ def load_data():
18
+ df = pd.read_json("data.json")
19
+ df = df.drop_duplicates()
20
+
21
+ return df
22
+
23
+
24
+ df = load_data()
25
+
26
+ # run_df_diagnostics(df, "Datos iniciales")
27
+
28
+
29
+ # Filters
30
+
31
+ st.sidebar.header("Filtros")
32
+
33
+ categorical_columns = {
34
+ "Titular": "titular",
35
+ "Título": "titulo",
36
+ "Uso amparado": "uso_amparado",
37
+ "Anotaciones marginales": "anotaciones_marginales",
38
+ "Tipo de anexo": "tipo_de_anexo",
39
+ "Estado": "estado",
40
+ "Municipio": "municipio",
41
+ "Región hidrológica": "region_hidrologica",
42
+ "Cuenca": "cuenca",
43
+ "Acuífero": "acuifero",
44
+ "Acuifero homologado": "acuifero_homologado",
45
+ }
46
+
47
+ st.sidebar.write("Filtrado por region via GeoJSON")
48
+ st.sidebar.write("Instrucciones: Entra a https://geojson.io/ y dibuja un poligono")
49
+ st.sidebar.write("Despues descarga el archivo como GeoJSON y cargalo aqui")
50
+ geojson = st.sidebar.file_uploader("Cargar GeoJSON", type=["geojson"])
51
+
52
+ if geojson is not None:
53
+ gdf = gpd.read_file(geojson)
54
+ df = gpd.GeoDataFrame(df)
55
+ df["geometry"] = df.apply(
56
+ lambda row: gpd.points_from_xy([row.lon], [row.lat])[0], axis=1
57
+ )
58
+ df.set_geometry("geometry")
59
+ df = gpd.sjoin(df, gdf, op="within")
60
+ df = df.drop(columns=["geometry", "index_right"])
61
+ df = pd.DataFrame(df)
62
+
63
+
64
+ columns = st.sidebar.multiselect(
65
+ "Selecciona columnas para filtrar por valor",
66
+ categorical_columns.keys(),
67
+ )
68
+
69
+ if columns:
70
+ for column in columns:
71
+ key = categorical_columns[column]
72
+ column_filters = st.sidebar.multiselect(
73
+ f"Selecciona valores para: {column}",
74
+ df[key].unique().tolist(),
75
+ )
76
+ if column_filters:
77
+ df = df[df[key].isin(column_filters)]
78
+
79
+ numeric_columns = {
80
+ "Volumen total de aguas nacionales": "volumen_total_de_aguas_nacionales",
81
+ "Volumen total de aguas superficiales": "volumen_total_de_aguas_superficiales",
82
+ "Volumen total de aguas subterráneas": "volumen_total_de_aguas_subterraneas",
83
+ "Volumen total de descargas": "volumen_total_de_descargas",
84
+ "Número de descargas en el título": "anexos_descargas",
85
+ "Número de tomas subtarráneas en el título": "anexos_subterraneos",
86
+ "Número de tomas superficiales en el título": "anexos_superficiales",
87
+ "Número de tomas en zonas federales en el título": "anexos_zonas_federales",
88
+ "Volumen individual": "volumen",
89
+ "Superficie": "superficie",
90
+ "Volumen de descarga diario": "volumen_de_descarga_diario",
91
+ "Volumen de descarga anual": "volumen_de_descarga_anual",
92
+ }
93
+
94
+ # Check if there are not None values in columns
95
+ numeric_columns_alive = {}
96
+ other_category_columns = (
97
+ set(df.columns.tolist())
98
+ - set(numeric_columns.values())
99
+ - set(categorical_columns.values())
100
+ )
101
+
102
+ other_catergory_columns_alive = {}
103
+ for key in other_category_columns:
104
+ if df[key].notnull().any():
105
+ other_catergory_columns_alive[key.capitalize().replace("_", " ")] = key
106
+
107
+ if other_catergory_columns_alive.keys() != []:
108
+ other_category_columns = st.sidebar.multiselect(
109
+ "Selecciona columnas para filtrar",
110
+ other_catergory_columns_alive.keys(),
111
+ )
112
+ if other_category_columns:
113
+ for key in other_category_columns:
114
+ column_name = other_catergory_columns_alive[key]
115
+ column_filters = st.sidebar.multiselect(
116
+ f"Selecciona valores para: {key}",
117
+ df[column_name].unique().tolist(),
118
+ )
119
+ if column_filters:
120
+ df = df[df[column_name].isin(column_filters)]
121
+
122
+ for key, column_name in numeric_columns.items():
123
+ if df[column_name].notnull().any():
124
+ if df[column_name].min() != df[column_name].max():
125
+ numeric_columns_alive[key] = column_name
126
+
127
+
128
+ if numeric_columns_alive.keys() != []:
129
+ numeric_column_filters = st.sidebar.multiselect(
130
+ "Selecciona columnas para filtrar por rango",
131
+ numeric_columns_alive.keys(),
132
+ )
133
+ if numeric_column_filters:
134
+ for key in numeric_column_filters:
135
+ column_name = numeric_columns_alive[key]
136
+ st.sidebar.write(f"Escoge un rango para: {key}")
137
+ min_value = st.sidebar.slider(
138
+ f"Valor mínimo para: {key}",
139
+ df[column_name].min(),
140
+ df[column_name].max(),
141
+ df[column_name].min(),
142
+ )
143
+ max_value = st.sidebar.slider(
144
+ f"Valor máximo para: {key}",
145
+ df[column_name].min(),
146
+ df[column_name].max(),
147
+ df[column_name].max(),
148
+ )
149
+ # drop rows that are NONE for that column
150
+
151
+ df = df[(df[column_name] >= min_value) & (df[column_name] <= max_value)]
152
+
153
+
154
+ # run_df_diagnostics(df, "Datos filtrados")
155
+
156
+
157
+ st.header("Mapa")
158
+
159
+
160
+ mapbox = px.scatter_mapbox(
161
+ df,
162
+ lat="lat",
163
+ lon="lon",
164
+ color="tipo_de_anexo",
165
+ hover_name="titular",
166
+ hover_data=[
167
+ "titulo",
168
+ "estado",
169
+ "municipio",
170
+ "region_hidrologica",
171
+ "cuenca",
172
+ "acuifero",
173
+ ],
174
+ color_discrete_sequence=px.colors.qualitative.Vivid,
175
+ zoom=4,
176
+ height=900,
177
+ width=1000,
178
+ center={"lat": 23.634501, "lon": -102.552784},
179
+ mapbox_style="carto-positron",
180
+ )
181
+ mapbox.update_traces(marker={"size": 8})
182
+
183
+ st.plotly_chart(mapbox)
184
+
185
+
186
+ st.header("Datos")
187
+
188
+ st.dataframe(df)
189
+
190
+ st.download_button(
191
+ label="Descargar datos",
192
+ data=df.to_csv().encode("utf-8"),
193
+ file_name="data.csv",
194
+ mime="text/csv",
195
+ )
app.py CHANGED
@@ -3,188 +3,294 @@ import pandas as pd
3
  import geopandas as gpd
4
  from diagnostics import run_df_diagnostics
5
  import plotly.express as px
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
 
 
 
8
  st.set_page_config(
9
- page_title="Explorador REPDA",
10
- page_icon="🧊",
11
  layout="wide",
12
  )
13
 
14
- st.title("Explorador REPDA")
 
 
15
 
16
 
17
- def load_data():
18
- df = pd.read_json("data.json")
19
- df = df.drop_duplicates()
 
 
 
20
 
21
- return df
22
 
 
 
23
 
24
- df = load_data()
25
 
26
- # run_df_diagnostics(df, "Datos iniciales")
27
 
 
28
 
29
- # Filters
 
 
 
 
30
 
31
  st.sidebar.header("Filtros")
32
 
33
- categorical_columns = {
34
- "Titular": "titular",
35
- "Título": "titulo",
36
- "Uso amparado": "uso_amparado",
37
- "Anotaciones marginales": "anotaciones_marginales",
38
- "Tipo de anexo": "tipo_de_anexo",
39
- "Estado": "estado",
40
- "Municipio": "municipio",
41
- "Región hidrológica": "region_hidrologica",
42
- "Cuenca": "cuenca",
43
- "Acuífero": "acuifero",
44
- "Acuifero homologado": "acuifero_homologado",
45
- }
46
 
47
- st.sidebar.write("Filtrado por region via GeoJSON")
48
- st.sidebar.write("Instrucciones: Entra a https://geojson.io/ y dibuja un poligono")
49
- st.sidebar.write("Despues descarga el archivo como GeoJSON y cargalo aqui")
50
- geojson = st.sidebar.file_uploader("Cargar GeoJSON", type=["geojson"])
51
 
52
- if geojson is not None:
53
- gdf = gpd.read_file(geojson)
54
- df = gpd.GeoDataFrame(df)
55
- df["geometry"] = df.apply(
56
- lambda row: gpd.points_from_xy([row.lon], [row.lat])[0], axis=1
57
- )
58
- df.set_geometry("geometry")
59
- df = gpd.sjoin(df, gdf, op="within")
60
- df = df.drop(columns=["geometry", "index_right"])
61
- df = pd.DataFrame(df)
62
 
63
 
64
- columns = st.sidebar.multiselect(
65
- "Selecciona columnas para filtrar por valor",
66
- categorical_columns.keys(),
67
- )
68
 
69
- if columns:
70
- for column in columns:
71
- key = categorical_columns[column]
72
- column_filters = st.sidebar.multiselect(
73
- f"Selecciona valores para: {column}",
74
- df[key].unique().tolist(),
75
- )
76
- if column_filters:
77
- df = df[df[key].isin(column_filters)]
78
-
79
- numeric_columns = {
80
- "Volumen total de aguas nacionales": "volumen_total_de_aguas_nacionales",
81
- "Volumen total de aguas superficiales": "volumen_total_de_aguas_superficiales",
82
- "Volumen total de aguas subterráneas": "volumen_total_de_aguas_subterraneas",
83
- "Volumen total de descargas": "volumen_total_de_descargas",
84
- "Número de descargas en el título": "anexos_descargas",
85
- "Número de tomas subtarráneas en el título": "anexos_subterraneos",
86
- "Número de tomas superficiales en el título": "anexos_superficiales",
87
- "Número de tomas en zonas federales en el título": "anexos_zonas_federales",
88
- "Volumen individual": "volumen",
89
- "Superficie": "superficie",
90
- "Volumen de descarga diario": "volumen_de_descarga_diario",
91
- "Volumen de descarga anual": "volumen_de_descarga_anual",
92
- }
93
 
94
- # Check if there are not None values in columns
95
- numeric_columns_alive = {}
96
- other_category_columns = (
97
- set(df.columns.tolist())
98
- - set(numeric_columns.values())
99
- - set(categorical_columns.values())
100
- )
101
-
102
- other_catergory_columns_alive = {}
103
- for key in other_category_columns:
104
- if df[key].notnull().any():
105
- other_catergory_columns_alive[key.capitalize().replace("_", " ")] = key
106
 
107
- if other_catergory_columns_alive.keys() != []:
108
- other_category_columns = st.sidebar.multiselect(
109
- "Selecciona columnas para filtrar",
110
- other_catergory_columns_alive.keys(),
111
- )
112
- if other_category_columns:
113
- for key in other_category_columns:
114
- column_name = other_catergory_columns_alive[key]
115
- column_filters = st.sidebar.multiselect(
116
- f"Selecciona valores para: {key}",
117
- df[column_name].unique().tolist(),
118
- )
119
- if column_filters:
120
- df = df[df[column_name].isin(column_filters)]
121
-
122
- for key, column_name in numeric_columns.items():
123
- if df[column_name].notnull().any():
124
- if df[column_name].min() != df[column_name].max():
125
- numeric_columns_alive[key] = column_name
126
-
127
-
128
- if numeric_columns_alive.keys() != []:
129
- numeric_column_filters = st.sidebar.multiselect(
130
- "Selecciona columnas para filtrar por rango",
131
- numeric_columns_alive.keys(),
132
- )
133
- if numeric_column_filters:
134
- for key in numeric_column_filters:
135
- column_name = numeric_columns_alive[key]
136
- st.sidebar.write(f"Escoge un rango para: {key}")
137
- min_value = st.sidebar.slider(
138
- f"Valor mínimo para: {key}",
139
- df[column_name].min(),
140
- df[column_name].max(),
141
- df[column_name].min(),
142
- )
143
- max_value = st.sidebar.slider(
144
- f"Valor máximo para: {key}",
145
- df[column_name].min(),
146
- df[column_name].max(),
147
- df[column_name].max(),
148
- )
149
- # drop rows that are NONE for that column
150
 
151
- df = df[(df[column_name] >= min_value) & (df[column_name] <= max_value)]
152
 
 
 
 
 
 
 
153
 
154
- # run_df_diagnostics(df, "Datos filtrados")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
 
157
- st.header("Mapa")
158
 
 
159
 
160
- mapbox = px.scatter_mapbox(
161
- df,
162
  lat="lat",
163
  lon="lon",
164
- color="tipo_de_anexo",
165
- hover_name="titular",
166
- hover_data=[
167
- "titulo",
168
- "estado",
169
- "municipio",
170
- "region_hidrologica",
171
- "cuenca",
172
- "acuifero",
173
- ],
174
- color_discrete_sequence=px.colors.qualitative.Vivid,
175
- zoom=4,
176
- height=900,
177
  width=1000,
178
- center={"lat": 23.634501, "lon": -102.552784},
 
 
179
  mapbox_style="carto-positron",
 
 
 
 
180
  )
181
- mapbox.update_traces(marker={"size": 8})
182
-
183
- st.plotly_chart(mapbox)
184
-
185
 
186
- st.header("Datos")
187
 
 
 
188
  st.dataframe(df)
189
 
190
  st.download_button(
 
3
  import geopandas as gpd
4
  from diagnostics import run_df_diagnostics
5
  import plotly.express as px
6
+ from streamlit_option_menu import option_menu
7
+
8
+
9
+ # Utils
10
+
11
+
12
+ def exclusive_categorical_search(df, filters: dict[str, list[str]]):
13
+ filtered_df = df.copy()
14
+ for column, values in filters.items():
15
+ if "Todos" in values:
16
+ continue
17
+ filtered_df = filtered_df[filtered_df[column].isin(values)]
18
+
19
+ # [ 1, 2, 3, 4] -> [TRUE, FALSE, TRUE, FALSE] -> [1, 3]
20
+ # [1, 3] -> [False, TRUE, ] -> [3]
21
+ # True and True -> True
22
+ # False and True -> False
23
+
24
+ return filtered_df
25
+
26
+
27
+ def exclusive_numerical_search(df, filters: dict[str, list[float]]):
28
+ """Performs an exclusive search on a dataframe
29
+ Args:
30
+ df (pd.DataFrame): Dataframe to search
31
+ filters (dict[str, list[float]]): Dictionary of filters with a list of two values min and max
32
+ """
33
+ filtered_df = df.copy()
34
+ for column, values in filters.items():
35
+ filtered_df = filtered_df[filtered_df[column] >= values[0]]
36
+ filtered_df = filtered_df[filtered_df[column] <= values[1]]
37
+
38
+ # [ 1, 2, 3, 4] -> [TRUE, FALSE, TRUE, FALSE] -> [1, 3]
39
+ # [1, 3] -> [False, TRUE, ] -> [3]
40
+ # True and True -> True
41
+ # False and True -> False
42
+ return filtered_df
43
+
44
+
45
+ def inclusive_categorical_search(df: pd.DataFrame, filters: dict[str, list[str]]):
46
+ filtered_dfs = []
47
+ if len(filters) == 0:
48
+ return df
49
+ for column, values in filters.items():
50
+ st.write(column)
51
+ if "Todos" in values:
52
+ filtered_dfs.append(df)
53
+ continue
54
+ filtered_dfs.append(df[df[column].isin(values)])
55
+ filtered_df = pd.concat(filtered_dfs)
56
+ filtered_df = filtered_df.drop_duplicates()
57
+
58
+ # d1 [1, 2, 3, 4] -> [TRUE, FALSE, TRUE, FALSE] -> [1, 3]
59
+ # d2 [1, 2, 3, 4] -> [FALSE, TRUE, TRUE, FALSE] -> [2, 3]
60
+ # [1, 3] + [2, 3] -> [1, 3, 2, 3] -> [1, 3, 2, 3]
61
+ # [1, 3, 2, 3] -> [1, 3, 2]
62
+
63
+ return filtered_df
64
+
65
+
66
+ def inclusive_numerical_search(df: pd.DataFrame, filters: dict[str, list[float]]):
67
+ filtered_dfs = []
68
+ if len(filters) == 0:
69
+ return df
70
+ for column, values in filters.items():
71
+ column = get_option_value(column)
72
+ temp_df = df.copy()
73
+ temp_df = temp_df[temp_df[column] >= values[0]]
74
+ temp_df = temp_df[temp_df[column] <= values[1]]
75
+ filtered_dfs.append(temp_df)
76
+ filtered_df = pd.concat(filtered_dfs)
77
+ filtered_df = filtered_df.drop_duplicates()
78
+
79
+ # d1 [1, 2, 3, 4] -> [TRUE, FALSE, TRUE, FALSE] -> [1, 3]
80
+ # d2 [1, 2, 3, 4] -> [FALSE, TRUE, TRUE, FALSE] -> [2, 3]
81
+ # [1, 3] + [2, 3] -> [1, 3, 2, 3] -> [1, 3, 2, 3]
82
+ # [1, 3, 2, 3] -> [1, 3, 2]
83
+
84
+ return filtered_df
85
+
86
+
87
+ # CONSTANTS
88
+ CATEGORICAL_COLUMNS = {
89
+ "Titular": "titular",
90
+ # "Título": "titulo",
91
+ "Uso amparado": "uso_amparado",
92
+ # "Anotaciones marginales": "anotaciones_marginales",
93
+ # "Tipo de anexo": "tipo_de_anexo",
94
+ # "Estado": "estado",
95
+ "Municipio": "municipio",
96
+ # "Región hidrológica": "region_hidrologica",
97
+ # "Cuenca": "cuenca",
98
+ "Acuífero": "acuifero",
99
+ # "Acuifero homologado": "acuifero_homologado",
100
+ }
101
 
102
+ NUMERIC_COLUMNS = {
103
+ # "Volumen total de aguas nacionales": "volumen_total_de_aguas_nacionales",
104
+ # "Volumen total de aguas superficiales": "volumen_total_de_aguas_superficiales",
105
+ # "Volumen total de aguas subterráneas": "volumen_total_de_aguas_subterraneas",
106
+ # "Volumen total de descargas": "volumen_total_de_descargas",
107
+ # "Número de descargas en el título": "anexos_descargas",
108
+ # "Número de tomas subtarráneas en el título": "anexos_subterraneos",
109
+ # "Número de tomas superficiales en el título": "anexos_superficiales",
110
+ # "Número de tomas en zonas federales en el título": "anexos_zonas_federales",
111
+ "Volumen de extracción": "volumen",
112
+ # "Superficie": "superficie",
113
+ # "Volumen de descarga diario": "volumen_de_descarga_diario",
114
+ "Volumen de descarga anual": "volumen_de_descarga_anual",
115
+ }
116
+
117
+
118
+ def get_option_value(key):
119
+ if key in CATEGORICAL_COLUMNS.keys():
120
+ return CATEGORICAL_COLUMNS[key]
121
+ elif key in NUMERIC_COLUMNS.keys():
122
+ return NUMERIC_COLUMNS[key]
123
+ else:
124
+ return None
125
 
126
+
127
+ # PAGE CONFIG
128
  st.set_page_config(
129
+ page_title="Explorador de datos REPDA Guanajuato",
130
+ page_icon="💧",
131
  layout="wide",
132
  )
133
 
134
+ _, cent_co, _ = st.columns(3)
135
+ with cent_co:
136
+ st.image("media/logo-poplab.png", width=500, use_column_width=True)
137
 
138
 
139
+ st.title("Explorador de datos REPDA Guanajuato")
140
+ st.subheader("Datos de concesiones de aguas nacionales en Guanajuato")
141
+ st.markdown("""
142
+ <iframe src="https://poplab.mx/dataCenter/pozos/counter"
143
+ style="width: 100%; height: 1px; border: none; position: absolute; top: 0; left: 0; right: 0; bottom: 0;"
144
+ ></iframe>
145
 
146
+ <div style="text-align: justify;max-width: 800px;">
147
 
148
+ Este explorador permite filtrar y examinar los datos de concesiones de aguas nacionales en Guanajuato.
149
+ Los datos han sido obtenidos del Registro Público de Derechos de Agua (REPDA) y han sido procesados para su visualización y análisis.
150
 
151
+ #### Instrucciones
152
 
153
+ En el menú de la izquierda, se podran realizar filtros categóricos y numéricos para explorar los datos.
154
 
155
+ Arriba del mapa se podrá seleccionar una columna para colorear el mapa. También se podrán seleccionar las columnas para visualizar al pasar el cursor sobre los puntos del mapa.
156
 
157
+ **Nota:** Algunos datos no cuentan con coordenadas, por lo que se les asignó latitud y longitud 1.
158
+
159
+ </div>
160
+ """, unsafe_allow_html=True
161
+ )
162
 
163
  st.sidebar.header("Filtros")
164
 
165
+ # DATA LOADING
 
 
 
 
 
 
 
 
 
 
 
 
166
 
 
 
 
 
167
 
168
+ @st.cache_data
169
+ def load_complete_data():
170
+ df = pd.read_json("data.json")
171
+ df = df.drop_duplicates()
172
+ return df
 
 
 
 
 
173
 
174
 
175
+ options = ["Explorador de datos filtrados", "Explorador de datos completos del REPDA"]
 
 
 
176
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
 
178
+ df = load_complete_data()
179
+ # run_df_diagnostics(df, "Datos iniciales")
 
 
 
 
 
 
 
 
 
 
180
 
181
+ # color = st.sidebar.selectbox(
182
+ # "Selecciona una columna para colorear el mapa", list(CATEGORICAL_COLUMNS.keys()), index=0
183
+ # )
184
+ # if not color:
185
+ # color = "Estado"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
 
187
+ filters = {}
188
 
189
+ categorical_search_type = "Inclusiva"
190
+ st.sidebar.subheader("Categorías")
191
+ active_filters = st.sidebar.multiselect(
192
+ "Filtros activos",
193
+ list(CATEGORICAL_COLUMNS.keys()),
194
+ )
195
 
196
+ for column_name in active_filters:
197
+ column = get_option_value(column_name)
198
+ st.sidebar.write(f"Selecciona {column}")
199
+ options = df[column].unique().tolist()
200
+ if column == "estado":
201
+ options = sorted(options)
202
+ options.insert(0, "Todos")
203
+
204
+ values = st.sidebar.multiselect(
205
+ column,
206
+ options,
207
+ default=["Todos"],
208
+ )
209
+ filters[column] = values
210
+ st.sidebar.divider()
211
+
212
+ if categorical_search_type == "Inclusiva":
213
+ if len(filters) > 0:
214
+ filtered_df = inclusive_categorical_search(df, filters)
215
+ else:
216
+ filtered_df = df
217
+ else:
218
+ filtered_df = exclusive_categorical_search(df, filters)
219
+
220
+ st.sidebar.subheader("Volúmenes")
221
+ numerical_search_type = "Exclusiva"
222
+ active_filters = st.sidebar.multiselect(
223
+ "Filtros activos",
224
+ list(NUMERIC_COLUMNS.keys()),
225
+ )
226
 
227
+ numerical_filters = {}
228
+
229
+ for column_name in active_filters:
230
+ column = get_option_value(column_name)
231
+ range_type = st.sidebar.radio(f"Selecciona {column}", ["Mayor que", "Menor que", "Entre"])
232
+ min = filtered_df[column].min()
233
+ max = filtered_df[column].max()
234
+ if range_type == "Mayor que":
235
+ min_value = st.sidebar.slider(f"Valor mínimo para {column}", min_value=min, max_value=max, value=min)
236
+ max_value = max
237
+
238
+ elif range_type == "Menor que":
239
+ min_value = min
240
+ max_value = st.sidebar.slider(f"Valor máximo para {column}", min_value=min, max_value=max, value=max)
241
+ else:
242
+ min_value = st.sidebar.slider(f"Valor mínimo para {column}", min_value=min, max_value=max, value=min)
243
+ max_value = st.sidebar.slider(f"Valor máximo para {column}", min_value=min, max_value=max, value=max)
244
+ numerical_filters[column] = [min_value, max_value]
245
+ st.sidebar.divider()
246
+
247
+ if numerical_search_type == "Inclusiva":
248
+ if len(numerical_filters) > 0:
249
+ filtered_df = inclusive_numerical_search(filtered_df, numerical_filters)
250
+ else:
251
+ filtered_df = filtered_df
252
+ else:
253
+ filtered_df = exclusive_numerical_search(filtered_df, numerical_filters)
254
+
255
+
256
+ color_options = list(CATEGORICAL_COLUMNS.keys()) + list(NUMERIC_COLUMNS.keys())
257
+ hover_options = color_options.copy() + ["lat", "lon"]
258
+ color_options.remove("Titular")
259
+ # color_options.remove("Título")
260
+
261
+ color = st.selectbox("Selecciona una columna para colorear el mapa", color_options, index=2)
262
+
263
+ hover = st.multiselect(
264
+ "Selecciona columnas para visualizar al pasar el cursor sobre los puntos del mapa",
265
+ hover_options,
266
+ default=["lat", "lon", "Titular"],
267
+ )
268
 
269
+ # st.plotly_chart(px.colors.qualitative.swatches())
270
 
271
+ # st.plotly_chart(px.colors.sequential.swatches())
272
 
273
+ fig = px.scatter_mapbox(
274
+ filtered_df,
275
  lat="lat",
276
  lon="lon",
277
+ # color=CATEGORICAL_COLUMNS[color],
278
+ color=get_option_value(color),
 
 
 
 
 
 
 
 
 
 
 
279
  width=1000,
280
+ height=600,
281
+ hover_name="titulo",
282
+ hover_data=map(get_option_value, hover),
283
  mapbox_style="carto-positron",
284
+ color_continuous_scale=px.colors.sequential.Reds,
285
+ color_discrete_sequence=px.colors.qualitative.Dark24,
286
+ center={"lat": 23.634501, "lon": -102.552784},
287
+ zoom=4,
288
  )
 
 
 
 
289
 
290
+ fig.update_traces(marker=dict(size=8, opacity=0.4))
291
 
292
+ st.plotly_chart(fig)
293
+ # st.write("Algunos datos no cuentan con coordenadas, por lo que se les asignó latitud y longitud 1")
294
  st.dataframe(df)
295
 
296
  st.download_button(
media/logo-poplab.png ADDED