Upload depth_interactive_map_alpha.R
Browse files- depth_interactive_map_alpha.R +151 -62
depth_interactive_map_alpha.R
CHANGED
|
@@ -204,15 +204,22 @@ FOSAS_COLS <- list(
|
|
| 204 |
"cuerpos" = list(col = "cuerpos_total", breaks = c(1, 10, 30, 80, 200))
|
| 205 |
)
|
| 206 |
|
| 207 |
-
# CPV 2020 population sub-types
|
| 208 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
| 209 |
POP_COLS <- list(
|
| 210 |
"POBTOT" = list(col = "pobtot", label = "Total population",
|
| 211 |
-
|
|
|
|
| 212 |
"PNACOP" = list(col = "pnacop", label = "Born abroad",
|
| 213 |
-
|
|
|
|
| 214 |
"PRESOP2015" = list(col = "presop2015", label = "Resident abroad (2015)",
|
| 215 |
-
|
|
|
|
| 216 |
)
|
| 217 |
|
| 218 |
# PATP sub-types (kind controls paint family: "num" = step, "cat" = match).
|
|
@@ -374,6 +381,28 @@ WEB_SQL_TEMPLATES <- list(
|
|
| 374 |
FROM dim_pam_mun GROUP BY CVEGEO) p
|
| 375 |
ON c.CVEGEO = p.CVEGEO",
|
| 376 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 377 |
# patp: dim_patp_mun stores numeric values as VARCHAR; TRY_CAST converts
|
| 378 |
# the 'n.d.' sentinels (and other non-numeric strings) to NULL.
|
| 379 |
src_patp =
|
|
@@ -549,7 +578,10 @@ web_sql_qbreaks <- function(tbl, col, n_colors, filter_zero = TRUE) {
|
|
| 549 |
# grid_crosswalk has codigo_n4..codigo_n8, so the equi-join always applies.
|
| 550 |
# simplify_tol: degrees of simplification applied to g.wkt at query time
|
| 551 |
# (0 = no simplification; default 0.005 deg ~= 500 m, suitable for N4-N6).
|
| 552 |
-
web_sql_grid_unified <- function(niv, has_fosas, limit = NULL, simplify_tol = 0.005
|
|
|
|
|
|
|
|
|
|
| 553 |
col_n <- paste0("codigo_n", niv)
|
| 554 |
limit_clause <- if (!is.null(limit)) paste0("\nLIMIT ", limit) else ""
|
| 555 |
wkt_expr <- if (simplify_tol > 0)
|
|
@@ -562,6 +594,40 @@ web_sql_grid_unified <- function(niv, has_fosas, limit = NULL, simplify_tol = 0.
|
|
| 562 |
fosas_join <- if (has_fosas)
|
| 563 |
"\n LEFT JOIN dim_fosas_mun f ON g.CVEGEO = f.CVEGEO"
|
| 564 |
else ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 565 |
# Subqueries ensure exactly one row per CVEGEO; direct joins on multi-row
|
| 566 |
# tables (dim_desap_mun ~58k rows, dim_pam_mun ~7.5k rows) explode memory.
|
| 567 |
desap_sub <- "(SELECT CVEGEO, AVG(final_desap_nl_per_100k) AS desap_rate FROM dim_desap_mun GROUP BY CVEGEO)"
|
|
@@ -608,26 +674,14 @@ web_sql_grid_unified <- function(niv, has_fosas, limit = NULL, simplify_tol = 0.
|
|
| 608 |
CAST(c.secuestro AS DOUBLE) AS secuestro,
|
| 609 |
CAST(c.trafico_menores AS DOUBLE) AS trafico_menores,
|
| 610 |
CAST(c.trata_personas AS DOUBLE) AS trata_personas,
|
| 611 |
-
|
| 612 |
-
-- INEGI's confidentiality suppression marker, normalised to NULL.
|
| 613 |
-
CASE WHEN cpv.pobtot < 0 THEN NULL ELSE CAST(cpv.pobtot AS DOUBLE) END AS pobtot,
|
| 614 |
-
CASE WHEN cpv.pnacop < 0 THEN NULL ELSE CAST(cpv.pnacop AS DOUBLE) END AS pnacop,
|
| 615 |
-
CASE WHEN cpv.presop2015 < 0 THEN NULL ELSE CAST(cpv.presop2015 AS DOUBLE) END AS presop2015,
|
| 616 |
COALESCE(CAST(d.desap_rate AS DOUBLE), 0) AS desap_per_100k{fosas_cols},
|
| 617 |
COALESCE(r.giim_mun, 'No aplica') AS giim_mun,
|
| 618 |
COALESCE(CAST(p.pam_total AS INTEGER), 0) AS pam_n,
|
| 619 |
CAST(s.perception_insecurity_perc AS DOUBLE) AS insecurity_perc,
|
| 620 |
CAST(s.dark_figures_perc AS DOUBLE) AS dark_figures_perc,
|
| 621 |
-
|
| 622 |
-
|
| 623 |
-
TRY_CAST(patp.t_ocup AS DOUBLE) AS t_ocup,
|
| 624 |
-
TRY_CAST(patp.pr AS DOUBLE) AS pr,
|
| 625 |
-
CAST(patp.ind_conec AS DOUBLE) AS ind_conec,
|
| 626 |
-
patp.pr_pred_loc_rur AS pr_pred_loc_rur,
|
| 627 |
-
patp.delitos_fc_b_j_a AS delitos_fc_b_j_a,
|
| 628 |
-
-- pobreza_mun (CONEVAL 2020)
|
| 629 |
-
CAST(pob.pobreza_pct AS DOUBLE) AS pobreza_pct,
|
| 630 |
-
CAST(pob.pobreza_ext_pct AS DOUBLE) AS pobreza_ext_pct,
|
| 631 |
COALESCE(pts.migrants_n, 0) AS migrants_n,
|
| 632 |
COALESCE(pts.graves_n, 0) AS graves_n,
|
| 633 |
COALESCE(pts.ocved_n, 0) AS ocved_n,
|
|
@@ -638,10 +692,7 @@ web_sql_grid_unified <- function(niv, has_fosas, limit = NULL, simplify_tol = 0.
|
|
| 638 |
LEFT JOIN {desap_sub} d ON g.CVEGEO = d.CVEGEO{fosas_join}
|
| 639 |
LEFT JOIN dim_remesas_mun r ON g.CVEGEO = r.CVEGEO
|
| 640 |
LEFT JOIN {pam_sub} p ON g.CVEGEO = p.CVEGEO
|
| 641 |
-
LEFT JOIN state_polygons s ON s.CVE_ENT = SUBSTR(g.CVEGEO, 1, 2)
|
| 642 |
-
LEFT JOIN dim_pop_cpv_grid cpv ON cpv.codigo = g.codigo AND cpv.nivel = {niv}
|
| 643 |
-
LEFT JOIN dim_patp_mun patp ON patp.CVEGEO = g.CVEGEO
|
| 644 |
-
LEFT JOIN dim_pobreza_mun pob ON pob.CVEGEO = g.CVEGEO
|
| 645 |
LEFT JOIN pts_src pts ON g.codigo = pts.codigo{limit_clause}"
|
| 646 |
)
|
| 647 |
}
|
|
@@ -859,11 +910,12 @@ WEB_SPEC <- list(
|
|
| 859 |
list(id = "pam-choro", type = "fill", src = "src_pam",
|
| 860 |
geom = "polygon", color = "pam_qstep", value = "pam_n",
|
| 861 |
opacity = 0.7, visible = FALSE),
|
| 862 |
-
# pop-choro
|
| 863 |
-
#
|
| 864 |
-
#
|
| 865 |
-
|
| 866 |
-
|
|
|
|
| 867 |
opacity = 0.7, visible = FALSE),
|
| 868 |
# patp-choro and pobreza-choro are also GRID-ONLY (joined into grid_unified)
|
| 869 |
list(id = "patp-choro", type = "fill", src = NULL,
|
|
@@ -957,8 +1009,8 @@ WEB_SPEC <- list(
|
|
| 957 |
tooltip = "Railway lines used by migrants, including freight routes known as 'La Bestia'.",
|
| 958 |
legend = list(type = "line", color = "#9E2A3A", label = "Railway", dashed = TRUE)),
|
| 959 |
list(kind = "layer", value = "pop-choro",
|
| 960 |
-
label = "Population
|
| 961 |
-
tooltip = "Census 2020 population counts
|
| 962 |
legend = list(type = "ramp", pal = "pop", unit = " people")),
|
| 963 |
list(kind = "radios", group = "pop")
|
| 964 |
)),
|
|
@@ -2536,10 +2588,21 @@ server <- function(input, output, session) {
|
|
| 2536 |
if (!is.null(con)) DBI::dbDisconnect(con, shutdown = TRUE)
|
| 2537 |
})
|
| 2538 |
|
| 2539 |
-
# Check
|
| 2540 |
-
|
| 2541 |
-
|
| 2542 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2543 |
|
| 2544 |
# Tracks whether grid N7 layers were successfully added to the map
|
| 2545 |
is_3d <- reactiveVal(FALSE)
|
|
@@ -2664,12 +2727,13 @@ server <- function(input, output, session) {
|
|
| 2664 |
count_step_expr("pam_n", breaks, PAM_PAL)
|
| 2665 |
}
|
| 2666 |
|
| 2667 |
-
# CPV 2020
|
| 2668 |
-
#
|
| 2669 |
-
# (
|
| 2670 |
-
pop_grid_expr <- function(pop_type = "POBTOT") {
|
| 2671 |
-
info
|
| 2672 |
-
|
|
|
|
| 2673 |
}
|
| 2674 |
|
| 2675 |
# Envipe on the GRID: each grid cell carries its containing state's
|
|
@@ -2737,8 +2801,8 @@ server <- function(input, output, session) {
|
|
| 2737 |
"desap-choro" = isTRUE(lazy_added$desap),
|
| 2738 |
"remesas-choro" = isTRUE(lazy_added$remesas),
|
| 2739 |
"pam-choro" = isTRUE(lazy_added$pam),
|
| 2740 |
-
|
| 2741 |
-
|
| 2742 |
"patp-choro" = FALSE,
|
| 2743 |
"pobreza-choro" = FALSE,
|
| 2744 |
"fosas-choro" = isTRUE(lazy_added$fosas),
|
|
@@ -2790,6 +2854,15 @@ server <- function(input, output, session) {
|
|
| 2790 |
)
|
| 2791 |
}
|
| 2792 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2793 |
for (lid in NON_GRID_LAYERS) {
|
| 2794 |
if (!layer_ready(lid)) next
|
| 2795 |
prx <- prx |> set_layout_property(
|
|
@@ -3114,7 +3187,10 @@ server <- function(input, output, session) {
|
|
| 3114 |
nv_tol <- if (niv >= 7L) 0.002 else 0.005
|
| 3115 |
tryCatch({
|
| 3116 |
DBI::dbGetQuery(con,
|
| 3117 |
-
web_sql_grid_unified(niv, has_fosas_tbl, limit, simplify_tol = nv_tol
|
|
|
|
|
|
|
|
|
|
| 3118 |
sf::st_as_sf(wkt = "wkt", crs = 4326) |>
|
| 3119 |
dplyr::select(-wkt)
|
| 3120 |
}, error = function(e) { message("grid_nivel", niv, ": ", e$message); NULL })
|
|
@@ -3318,7 +3394,11 @@ server <- function(input, output, session) {
|
|
| 3318 |
observeEvent(input$grid_nivel, {
|
| 3319 |
req(input$grid_nivel == "7", !grid7_loaded(), !is.null(con))
|
| 3320 |
grid7_sf <<- tryCatch({
|
| 3321 |
-
DBI::dbGetQuery(con,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3322 |
sf::st_as_sf(wkt = "wkt", crs = 4326) |>
|
| 3323 |
dplyr::select(-wkt)
|
| 3324 |
}, error = function(e) { message("N7 lazy load: ", e$message); NULL })
|
|
@@ -3387,12 +3467,21 @@ server <- function(input, output, session) {
|
|
| 3387 |
nv_tol <- if (nv_chr == "7") 0.002 else 0.005
|
| 3388 |
sql <- if (has_pre) paste("SELECT * FROM", pre_tbl)
|
| 3389 |
else web_sql_grid_unified(as.integer(nv_chr), has_fosas_tbl,
|
| 3390 |
-
simplify_tol = nv_tol
|
|
|
|
|
|
|
|
|
|
| 3391 |
sf_data <- tryCatch({
|
| 3392 |
DBI::dbGetQuery(con, sql) |>
|
| 3393 |
sf::st_as_sf(wkt = "wkt", crs = 4326) |>
|
| 3394 |
dplyr::select(-wkt)
|
| 3395 |
-
}, error = function(e) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3396 |
if (!is.null(sf_data)) {
|
| 3397 |
maplibre_proxy("map") |> add_typed_grid_layers(sf_data, nv_chr)
|
| 3398 |
lazy_added[[key]] <<- TRUE
|
|
@@ -3427,7 +3516,14 @@ server <- function(input, output, session) {
|
|
| 3427 |
fill_color = pam_qstep_expr(), fill_opacity = 0.7,
|
| 3428 |
tooltip = list("concat", "<b>", list("get","municipio"), "</b>",
|
| 3429 |
"<br>Irregular migration events: ", list("to-string", list("get","pam_n")))))
|
| 3430 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3431 |
if (!grid_on && "fosas-choro" %in% active && has_fosas_tbl)
|
| 3432 |
lazy_add_fill("fosas", "src_fosas", "fosas-choro", function(prx, d)
|
| 3433 |
prx |> add_fill_layer("fosas-choro", source = d,
|
|
@@ -3495,19 +3591,12 @@ server <- function(input, output, session) {
|
|
| 3495 |
)
|
| 3496 |
updateSelectInput(session, "state_select",
|
| 3497 |
choices = c("Choose a state..." = "", state_ch))
|
| 3498 |
-
# Pre-materialise grid joins for N4/N5/N6
|
| 3499 |
-
#
|
| 3500 |
-
#
|
| 3501 |
-
|
| 3502 |
-
|
| 3503 |
-
|
| 3504 |
-
DBI::dbExecute(con, paste0(
|
| 3505 |
-
"CREATE TEMP TABLE IF NOT EXISTS grid_pre_n", .nv, " AS ",
|
| 3506 |
-
web_sql_grid_unified(as.integer(.nv), has_fosas_tbl, simplify_tol = nv_tol)
|
| 3507 |
-
)),
|
| 3508 |
-
error = function(e) message("grid_pre_n", .nv, ": ", e$message)
|
| 3509 |
-
)
|
| 3510 |
-
}
|
| 3511 |
}, once = TRUE)
|
| 3512 |
|
| 3513 |
# Grid overlay on/off is driven explicitly by resolution clicks in the menu
|
|
|
|
| 204 |
"cuerpos" = list(col = "cuerpos_total", breaks = c(1, 10, 30, 80, 200))
|
| 205 |
)
|
| 206 |
|
| 207 |
+
# CPV 2020 population sub-types. The same column name (e.g. pobtot) lives in
|
| 208 |
+
# both the per-cell grid join AND the muni-level aggregation, so step_expr can
|
| 209 |
+
# read either; only the BREAKS differ between modes.
|
| 210 |
+
# breaks_grid -> niv 4..7 cells (chosen on observed CPV ranges per nivel)
|
| 211 |
+
# breaks_mun -> per-municipality totals (CDMX/Monterrey/Guadalajara reach
|
| 212 |
+
# the millions; smallest munis a few hundred)
|
| 213 |
POP_COLS <- list(
|
| 214 |
"POBTOT" = list(col = "pobtot", label = "Total population",
|
| 215 |
+
breaks_grid = c(100, 1000, 5000, 25000, 100000, 500000),
|
| 216 |
+
breaks_mun = c(5000, 25000, 100000, 250000, 500000, 1000000)),
|
| 217 |
"PNACOP" = list(col = "pnacop", label = "Born abroad",
|
| 218 |
+
breaks_grid = c(5, 25, 100, 500, 2500, 10000),
|
| 219 |
+
breaks_mun = c(25, 100, 500, 2500, 10000, 50000)),
|
| 220 |
"PRESOP2015" = list(col = "presop2015", label = "Resident abroad (2015)",
|
| 221 |
+
breaks_grid = c(2, 10, 50, 250, 1000, 5000),
|
| 222 |
+
breaks_mun = c(10, 50, 250, 1000, 5000, 25000))
|
| 223 |
)
|
| 224 |
|
| 225 |
# PATP sub-types (kind controls paint family: "num" = step, "cat" = match).
|
|
|
|
| 381 |
FROM dim_pam_mun GROUP BY CVEGEO) p
|
| 382 |
ON c.CVEGEO = p.CVEGEO",
|
| 383 |
|
| 384 |
+
# Municipal-level CPV 2020 totals. Aggregates at nivel 8 (cell ~1.3km cell
|
| 385 |
+
# length, ~224k cells) so even the smallest CDMX delegaciones are larger than
|
| 386 |
+
# any cell and don't get inflated by single-cell over-attribution.
|
| 387 |
+
src_pop_mun =
|
| 388 |
+
"WITH agg AS (
|
| 389 |
+
SELECT g.CVEGEO,
|
| 390 |
+
SUM(CASE WHEN cpv.pobtot >= 0 THEN cpv.pobtot ELSE 0 END) AS pobtot,
|
| 391 |
+
SUM(CASE WHEN cpv.pnacop >= 0 THEN cpv.pnacop ELSE 0 END) AS pnacop,
|
| 392 |
+
SUM(CASE WHEN cpv.presop2015 >= 0 THEN cpv.presop2015 ELSE 0 END) AS presop2015
|
| 393 |
+
FROM grid_nivel8 g
|
| 394 |
+
LEFT JOIN dim_pop_cpv_grid cpv
|
| 395 |
+
ON cpv.codigo = g.codigo AND cpv.nivel = 8
|
| 396 |
+
GROUP BY g.CVEGEO
|
| 397 |
+
)
|
| 398 |
+
SELECT c.municipio, c.entidad, c.CVEGEO,
|
| 399 |
+
COALESCE(a.pobtot, 0) AS pobtot,
|
| 400 |
+
COALESCE(a.pnacop, 0) AS pnacop,
|
| 401 |
+
COALESCE(a.presop2015, 0) AS presop2015,
|
| 402 |
+
c.wkt
|
| 403 |
+
FROM crime_mun c
|
| 404 |
+
LEFT JOIN agg a ON a.CVEGEO = c.CVEGEO",
|
| 405 |
+
|
| 406 |
# patp: dim_patp_mun stores numeric values as VARCHAR; TRY_CAST converts
|
| 407 |
# the 'n.d.' sentinels (and other non-numeric strings) to NULL.
|
| 408 |
src_patp =
|
|
|
|
| 578 |
# grid_crosswalk has codigo_n4..codigo_n8, so the equi-join always applies.
|
| 579 |
# simplify_tol: degrees of simplification applied to g.wkt at query time
|
| 580 |
# (0 = no simplification; default 0.005 deg ~= 500 m, suitable for N4-N6).
|
| 581 |
+
web_sql_grid_unified <- function(niv, has_fosas, limit = NULL, simplify_tol = 0.005,
|
| 582 |
+
has_cpv_grid = TRUE,
|
| 583 |
+
has_patp = TRUE,
|
| 584 |
+
has_pobreza = TRUE) {
|
| 585 |
col_n <- paste0("codigo_n", niv)
|
| 586 |
limit_clause <- if (!is.null(limit)) paste0("\nLIMIT ", limit) else ""
|
| 587 |
wkt_expr <- if (simplify_tol > 0)
|
|
|
|
| 594 |
fosas_join <- if (has_fosas)
|
| 595 |
"\n LEFT JOIN dim_fosas_mun f ON g.CVEGEO = f.CVEGEO"
|
| 596 |
else ""
|
| 597 |
+
# Each optional extension is rendered as (columns + join) pairs. If the
|
| 598 |
+
# backing table is missing on the deployed DB, we substitute NULLs for the
|
| 599 |
+
# columns and skip the join entirely -- the rest of the grid still loads.
|
| 600 |
+
cpv_cols <- if (has_cpv_grid)
|
| 601 |
+
"CASE WHEN cpv.pobtot < 0 THEN NULL ELSE CAST(cpv.pobtot AS DOUBLE) END AS pobtot,
|
| 602 |
+
CASE WHEN cpv.pnacop < 0 THEN NULL ELSE CAST(cpv.pnacop AS DOUBLE) END AS pnacop,
|
| 603 |
+
CASE WHEN cpv.presop2015 < 0 THEN NULL ELSE CAST(cpv.presop2015 AS DOUBLE) END AS presop2015"
|
| 604 |
+
else
|
| 605 |
+
"CAST(NULL AS DOUBLE) AS pobtot, CAST(NULL AS DOUBLE) AS pnacop, CAST(NULL AS DOUBLE) AS presop2015"
|
| 606 |
+
cpv_join <- if (has_cpv_grid)
|
| 607 |
+
paste0("\n LEFT JOIN dim_pop_cpv_grid cpv ON cpv.codigo = g.codigo AND cpv.nivel = ", niv)
|
| 608 |
+
else ""
|
| 609 |
+
patp_cols <- if (has_patp)
|
| 610 |
+
"TRY_CAST(patp.t_part AS DOUBLE) AS t_part,
|
| 611 |
+
TRY_CAST(patp.t_ocup AS DOUBLE) AS t_ocup,
|
| 612 |
+
TRY_CAST(patp.pr AS DOUBLE) AS pr,
|
| 613 |
+
CAST(patp.ind_conec AS DOUBLE) AS ind_conec,
|
| 614 |
+
patp.pr_pred_loc_rur AS pr_pred_loc_rur,
|
| 615 |
+
patp.delitos_fc_b_j_a AS delitos_fc_b_j_a"
|
| 616 |
+
else
|
| 617 |
+
"CAST(NULL AS DOUBLE) AS t_part, CAST(NULL AS DOUBLE) AS t_ocup, CAST(NULL AS DOUBLE) AS pr,
|
| 618 |
+
CAST(NULL AS DOUBLE) AS ind_conec, CAST(NULL AS VARCHAR) AS pr_pred_loc_rur,
|
| 619 |
+
CAST(NULL AS VARCHAR) AS delitos_fc_b_j_a"
|
| 620 |
+
patp_join <- if (has_patp)
|
| 621 |
+
"\n LEFT JOIN dim_patp_mun patp ON patp.CVEGEO = g.CVEGEO"
|
| 622 |
+
else ""
|
| 623 |
+
pob_cols <- if (has_pobreza)
|
| 624 |
+
"CAST(pob.pobreza_pct AS DOUBLE) AS pobreza_pct,
|
| 625 |
+
CAST(pob.pobreza_ext_pct AS DOUBLE) AS pobreza_ext_pct"
|
| 626 |
+
else
|
| 627 |
+
"CAST(NULL AS DOUBLE) AS pobreza_pct, CAST(NULL AS DOUBLE) AS pobreza_ext_pct"
|
| 628 |
+
pob_join <- if (has_pobreza)
|
| 629 |
+
"\n LEFT JOIN dim_pobreza_mun pob ON pob.CVEGEO = g.CVEGEO"
|
| 630 |
+
else ""
|
| 631 |
# Subqueries ensure exactly one row per CVEGEO; direct joins on multi-row
|
| 632 |
# tables (dim_desap_mun ~58k rows, dim_pam_mun ~7.5k rows) explode memory.
|
| 633 |
desap_sub <- "(SELECT CVEGEO, AVG(final_desap_nl_per_100k) AS desap_rate FROM dim_desap_mun GROUP BY CVEGEO)"
|
|
|
|
| 674 |
CAST(c.secuestro AS DOUBLE) AS secuestro,
|
| 675 |
CAST(c.trafico_menores AS DOUBLE) AS trafico_menores,
|
| 676 |
CAST(c.trata_personas AS DOUBLE) AS trata_personas,
|
| 677 |
+
{cpv_cols},
|
|
|
|
|
|
|
|
|
|
|
|
|
| 678 |
COALESCE(CAST(d.desap_rate AS DOUBLE), 0) AS desap_per_100k{fosas_cols},
|
| 679 |
COALESCE(r.giim_mun, 'No aplica') AS giim_mun,
|
| 680 |
COALESCE(CAST(p.pam_total AS INTEGER), 0) AS pam_n,
|
| 681 |
CAST(s.perception_insecurity_perc AS DOUBLE) AS insecurity_perc,
|
| 682 |
CAST(s.dark_figures_perc AS DOUBLE) AS dark_figures_perc,
|
| 683 |
+
{patp_cols},
|
| 684 |
+
{pob_cols},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 685 |
COALESCE(pts.migrants_n, 0) AS migrants_n,
|
| 686 |
COALESCE(pts.graves_n, 0) AS graves_n,
|
| 687 |
COALESCE(pts.ocved_n, 0) AS ocved_n,
|
|
|
|
| 692 |
LEFT JOIN {desap_sub} d ON g.CVEGEO = d.CVEGEO{fosas_join}
|
| 693 |
LEFT JOIN dim_remesas_mun r ON g.CVEGEO = r.CVEGEO
|
| 694 |
LEFT JOIN {pam_sub} p ON g.CVEGEO = p.CVEGEO
|
| 695 |
+
LEFT JOIN state_polygons s ON s.CVE_ENT = SUBSTR(g.CVEGEO, 1, 2){cpv_join}{patp_join}{pob_join}
|
|
|
|
|
|
|
|
|
|
| 696 |
LEFT JOIN pts_src pts ON g.codigo = pts.codigo{limit_clause}"
|
| 697 |
)
|
| 698 |
}
|
|
|
|
| 910 |
list(id = "pam-choro", type = "fill", src = "src_pam",
|
| 911 |
geom = "polygon", color = "pam_qstep", value = "pam_n",
|
| 912 |
opacity = 0.7, visible = FALSE),
|
| 913 |
+
# pop-choro paints in BOTH modes:
|
| 914 |
+
# non-grid: per-municipality aggregate of CPV cells (src_pop_mun)
|
| 915 |
+
# grid: per-cell value at the active nivel (dim_pop_cpv_grid, joined
|
| 916 |
+
# into web_sql_grid_unified)
|
| 917 |
+
list(id = "pop-choro", type = "fill", src = "src_pop_mun",
|
| 918 |
+
geom = "polygon", color = "pop_qstep", value = "pobtot",
|
| 919 |
opacity = 0.7, visible = FALSE),
|
| 920 |
# patp-choro and pobreza-choro are also GRID-ONLY (joined into grid_unified)
|
| 921 |
list(id = "patp-choro", type = "fill", src = NULL,
|
|
|
|
| 1009 |
tooltip = "Railway lines used by migrants, including freight routes known as 'La Bestia'.",
|
| 1010 |
legend = list(type = "line", color = "#9E2A3A", label = "Railway", dashed = TRUE)),
|
| 1011 |
list(kind = "layer", value = "pop-choro",
|
| 1012 |
+
label = "Population (CPV 2020)",
|
| 1013 |
+
tooltip = "Census 2020 population counts. With the grid view off, each municipality shows the sum of its CPV cells (3 sub-types: total, born abroad, resident abroad in 2015). With the grid view on, each rHEALPix cell shows its own value at the active nivel (n4-n7).",
|
| 1014 |
legend = list(type = "ramp", pal = "pop", unit = " people")),
|
| 1015 |
list(kind = "radios", group = "pop")
|
| 1016 |
)),
|
|
|
|
| 2588 |
if (!is.null(con)) DBI::dbDisconnect(con, shutdown = TRUE)
|
| 2589 |
})
|
| 2590 |
|
| 2591 |
+
# Check optional tables once at session start. Each gates the SQL builders
|
| 2592 |
+
# so a missing table does not cascade into the rest of the grid_unified
|
| 2593 |
+
# query (which would otherwise blank all grid layers).
|
| 2594 |
+
tbl_exists <- function(t) {
|
| 2595 |
+
if (is.null(con)) return(FALSE)
|
| 2596 |
+
tryCatch(DBI::dbExistsTable(con, t), error = function(e) FALSE)
|
| 2597 |
+
}
|
| 2598 |
+
has_fosas_tbl <- tbl_exists("dim_fosas_mun")
|
| 2599 |
+
has_cpv_grid_tbl <- tbl_exists("dim_pop_cpv_grid")
|
| 2600 |
+
has_patp_tbl <- tbl_exists("dim_patp_mun")
|
| 2601 |
+
has_pobreza_tbl <- tbl_exists("dim_pobreza_mun")
|
| 2602 |
+
message("[deploy-check] dim_pop_cpv_grid=", has_cpv_grid_tbl,
|
| 2603 |
+
" dim_patp_mun=", has_patp_tbl,
|
| 2604 |
+
" dim_pobreza_mun=", has_pobreza_tbl,
|
| 2605 |
+
" dim_fosas_mun=", has_fosas_tbl)
|
| 2606 |
|
| 2607 |
# Tracks whether grid N7 layers were successfully added to the map
|
| 2608 |
is_3d <- reactiveVal(FALSE)
|
|
|
|
| 2727 |
count_step_expr("pam_n", breaks, PAM_PAL)
|
| 2728 |
}
|
| 2729 |
|
| 2730 |
+
# CPV 2020 population paint. mode = "grid" reads per-cell values (joined into
|
| 2731 |
+
# web_sql_grid_unified); mode = "mun" reads per-municipality aggregates
|
| 2732 |
+
# (src_pop_mun). Same column name in both modes; only the breaks differ.
|
| 2733 |
+
pop_grid_expr <- function(pop_type = "POBTOT", mode = "grid") {
|
| 2734 |
+
info <- POP_COLS[[pop_type]] %||% POP_COLS[["POBTOT"]]
|
| 2735 |
+
breaks <- if (identical(mode, "mun")) info$breaks_mun else info$breaks_grid
|
| 2736 |
+
step_expr(info$col, breaks, POP_PAL)
|
| 2737 |
}
|
| 2738 |
|
| 2739 |
# Envipe on the GRID: each grid cell carries its containing state's
|
|
|
|
| 2801 |
"desap-choro" = isTRUE(lazy_added$desap),
|
| 2802 |
"remesas-choro" = isTRUE(lazy_added$remesas),
|
| 2803 |
"pam-choro" = isTRUE(lazy_added$pam),
|
| 2804 |
+
"pop-choro" = isTRUE(lazy_added$pop),
|
| 2805 |
+
# patp / pobreza remain grid-only -- no mun-level layer to gate.
|
| 2806 |
"patp-choro" = FALSE,
|
| 2807 |
"pobreza-choro" = FALSE,
|
| 2808 |
"fosas-choro" = isTRUE(lazy_added$fosas),
|
|
|
|
| 2854 |
)
|
| 2855 |
}
|
| 2856 |
|
| 2857 |
+
# Sync pop fill color to selected sub-type (POBTOT / PNACOP / PRESOP2015)
|
| 2858 |
+
# when grid is OFF. Uses mun-mode breaks via pop_grid_expr(mode = "mun").
|
| 2859 |
+
if (!grid_on && "pop-choro" %in% active && layer_ready("pop-choro")) {
|
| 2860 |
+
prx <- prx |> set_paint_property(
|
| 2861 |
+
"pop-choro", "fill-color",
|
| 2862 |
+
pop_grid_expr(pop_type, "mun")
|
| 2863 |
+
)
|
| 2864 |
+
}
|
| 2865 |
+
|
| 2866 |
for (lid in NON_GRID_LAYERS) {
|
| 2867 |
if (!layer_ready(lid)) next
|
| 2868 |
prx <- prx |> set_layout_property(
|
|
|
|
| 3187 |
nv_tol <- if (niv >= 7L) 0.002 else 0.005
|
| 3188 |
tryCatch({
|
| 3189 |
DBI::dbGetQuery(con,
|
| 3190 |
+
web_sql_grid_unified(niv, has_fosas_tbl, limit, simplify_tol = nv_tol,
|
| 3191 |
+
has_cpv_grid = has_cpv_grid_tbl,
|
| 3192 |
+
has_patp = has_patp_tbl,
|
| 3193 |
+
has_pobreza = has_pobreza_tbl)) |>
|
| 3194 |
sf::st_as_sf(wkt = "wkt", crs = 4326) |>
|
| 3195 |
dplyr::select(-wkt)
|
| 3196 |
}, error = function(e) { message("grid_nivel", niv, ": ", e$message); NULL })
|
|
|
|
| 3394 |
observeEvent(input$grid_nivel, {
|
| 3395 |
req(input$grid_nivel == "7", !grid7_loaded(), !is.null(con))
|
| 3396 |
grid7_sf <<- tryCatch({
|
| 3397 |
+
DBI::dbGetQuery(con,
|
| 3398 |
+
web_sql_grid_unified(7, has_fosas_tbl, simplify_tol = 0.002,
|
| 3399 |
+
has_cpv_grid = has_cpv_grid_tbl,
|
| 3400 |
+
has_patp = has_patp_tbl,
|
| 3401 |
+
has_pobreza = has_pobreza_tbl)) |>
|
| 3402 |
sf::st_as_sf(wkt = "wkt", crs = 4326) |>
|
| 3403 |
dplyr::select(-wkt)
|
| 3404 |
}, error = function(e) { message("N7 lazy load: ", e$message); NULL })
|
|
|
|
| 3467 |
nv_tol <- if (nv_chr == "7") 0.002 else 0.005
|
| 3468 |
sql <- if (has_pre) paste("SELECT * FROM", pre_tbl)
|
| 3469 |
else web_sql_grid_unified(as.integer(nv_chr), has_fosas_tbl,
|
| 3470 |
+
simplify_tol = nv_tol,
|
| 3471 |
+
has_cpv_grid = has_cpv_grid_tbl,
|
| 3472 |
+
has_patp = has_patp_tbl,
|
| 3473 |
+
has_pobreza = has_pobreza_tbl)
|
| 3474 |
sf_data <- tryCatch({
|
| 3475 |
DBI::dbGetQuery(con, sql) |>
|
| 3476 |
sf::st_as_sf(wkt = "wkt", crs = 4326) |>
|
| 3477 |
dplyr::select(-wkt)
|
| 3478 |
+
}, error = function(e) {
|
| 3479 |
+
message("lazy grid n", nv_chr, ": ", e$message)
|
| 3480 |
+
try(showNotification(paste0("Grid n", nv_chr, " load failed: ",
|
| 3481 |
+
conditionMessage(e)),
|
| 3482 |
+
type = "error", duration = 12), silent = TRUE)
|
| 3483 |
+
NULL
|
| 3484 |
+
})
|
| 3485 |
if (!is.null(sf_data)) {
|
| 3486 |
maplibre_proxy("map") |> add_typed_grid_layers(sf_data, nv_chr)
|
| 3487 |
lazy_added[[key]] <<- TRUE
|
|
|
|
| 3516 |
fill_color = pam_qstep_expr(), fill_opacity = 0.7,
|
| 3517 |
tooltip = list("concat", "<b>", list("get","municipio"), "</b>",
|
| 3518 |
"<br>Irregular migration events: ", list("to-string", list("get","pam_n")))))
|
| 3519 |
+
if (!grid_on && "pop-choro" %in% active && has_cpv_grid_tbl)
|
| 3520 |
+
lazy_add_fill("pop", "src_pop_mun", "pop-choro", function(prx, d)
|
| 3521 |
+
prx |> add_fill_layer("pop-choro", source = d,
|
| 3522 |
+
fill_color = pop_grid_expr("POBTOT", "mun"), fill_opacity = 0.7,
|
| 3523 |
+
tooltip = list("concat", "<b>", list("get","municipio"), "</b>",
|
| 3524 |
+
"<br>Total pop (CPV): ", list("to-string", list("get","pobtot")),
|
| 3525 |
+
"<br>Born abroad: ", list("to-string", list("get","pnacop")),
|
| 3526 |
+
"<br>Resident abroad 2015: ", list("to-string", list("get","presop2015")))))
|
| 3527 |
if (!grid_on && "fosas-choro" %in% active && has_fosas_tbl)
|
| 3528 |
lazy_add_fill("fosas", "src_fosas", "fosas-choro", function(prx, d)
|
| 3529 |
prx |> add_fill_layer("fosas-choro", source = d,
|
|
|
|
| 3591 |
)
|
| 3592 |
updateSelectInput(session, "state_select",
|
| 3593 |
choices = c("Choose a state..." = "", state_ch))
|
| 3594 |
+
# Pre-materialise grid joins for N4/N5/N6 -- TEMPORARILY DISABLED.
|
| 3595 |
+
# The extended grid_unified CTE was blocking session startup on HF (3
|
| 3596 |
+
# synchronous queries against a query with 9 LEFT JOINs). lazy_add_grid()
|
| 3597 |
+
# now falls back to the direct CTE on first user click, which finishes
|
| 3598 |
+
# within a few seconds and lets the user keep using the rest of the app.
|
| 3599 |
+
# If this proves OK on HF, re-enable with a background/async strategy.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3600 |
}, once = TRUE)
|
| 3601 |
|
| 3602 |
# Grid overlay on/off is driven explicitly by resolution clicks in the menu
|