"""Etapa 4: exporta os resultados para o mapa interativo em ../mapa/. Gera arquivos pequenos e só com dados agregados: - mapa/dados.json: por município e grupo, observados, esperados e RMP suavizada - mapa/municipios.geojson e mapa/ufs.geojson: malhas do IBGE com coordenadas arredondadas - mapa/sinais.csv e mapa/municipios_rmp.csv: resultados completos para download Uso: python gerar_mapa.py """ import json import shutil from pathlib import Path import pandas as pd from analisar import CRITERIO from config import ANOS, BRUTOS, GRUPOS, MAPA, RESULTADOS def arredondar(coords, casas=3): if isinstance(coords[0], (int, float)): return [round(coords[0], casas), round(coords[1], casas)] return [arredondar(c, casas) for c in coords] def malha(origem, destino, chave): geo = json.loads(origem.read_text()) for f in geo["features"]: cod = f["properties"].get("codarea") f["properties"] = {chave: int(cod)} f["geometry"]["coordinates"] = arredondar(f["geometry"]["coordinates"]) destino.write_text(json.dumps(geo, separators=(",", ":"))) def preview_svg(grupo, destino): """Mapa estático leve (contorno dos estados + sinais prioritários) para a página inicial.""" import math ufs = json.loads((BRUTOS / "malha_ufs.geojson").read_text()) muns = json.loads((BRUTOS / "malha_municipios.geojson").read_text()) sinais = pd.read_csv(RESULTADOS / "sinais.csv") sinais = sinais[(sinais["nome_grupo"] == GRUPOS[grupo]["nome"]) & (sinais["contexto"] == "prioritário")] alvo = set(sinais["cod_ibge"]) lon0, lon1, lat0, lat1 = -74.2, -34.6, -34.0, 5.4 k = math.cos(math.radians(-15)) largura = 520 escala = largura / ((lon1 - lon0) * k) altura = round((lat1 - lat0) * escala) def xy(lon, lat): return round((lon - lon0) * k * escala, 1), round((lat1 - lat) * escala, 1) def aneis(geom): polys = geom["coordinates"] if geom["type"] == "MultiPolygon" else [geom["coordinates"]] return [anel for poly in polys for anel in poly[:1]] caminhos = [] for f in ufs["features"]: for anel in aneis(f["geometry"]): pts = [xy(*p) for p in anel[::2]] if len(pts) > 3: caminhos.append("M" + "L".join(f"{x},{y}" for x, y in pts) + "Z") pontos = [] for f in muns["features"]: if int(f["properties"]["codarea"]) in alvo: coords = [p for anel in aneis(f["geometry"]) for p in anel] lon = (min(p[0] for p in coords) + max(p[0] for p in coords)) / 2 lat = (min(p[1] for p in coords) + max(p[1] for p in coords)) / 2 pontos.append(xy(lon, lat)) svg = [f'', f''] for x, y in pontos: svg.append(f'' f'') svg.append("") destino.write_text("".join(svg)) def num(x, casas): return None if pd.isna(x) else round(float(x), casas) def main(): MAPA.mkdir(parents=True, exist_ok=True) res = pd.read_csv(RESULTADOS / "municipios_rmp.csv") muns = (res[["cod_ibge", "municipio", "uf_sigla", "populacao", "pct_mal_definidas"]] .drop_duplicates("cod_ibge").sort_values("cod_ibge")) ordem = muns["cod_ibge"].tolist() dados = { "anos": [ANOS[0], ANOS[-1]], "criterio": CRITERIO, "grupos": {g: {"nome": d["nome"], "en": d["en"]} for g, d in GRUPOS.items()}, "municipios": { "cod": ordem, "nome": muns["municipio"].tolist(), "uf": muns["uf_sigla"].tolist(), "pop": muns["populacao"].astype(int).tolist(), "mal_def": [num(v, 1) for v in muns["pct_mal_definidas"]], }, "valores": {}, } for g in GRUPOS: d = res[res["grupo"] == g].set_index("cod_ibge").reindex(ordem) dados["valores"][g] = { "obs": d["observados"].fillna(0).astype(int).tolist(), "esp_uf": [num(v, 1) for v in d["esperados_uf"]], "rmp_uf": [num(v, 2) for v in d["rmp_suav_uf"]], "bruta_uf": [num(v, 2) for v in d["rmp_uf"]], "ic_uf": [[num(a, 2), num(b, 2)] for a, b in zip(d["ic95_inf_uf"], d["ic95_sup_uf"])], "bruta_br": [num(v, 2) for v in d["rmp_br"]], "esp_br": [num(v, 1) for v in d["esperados_br"]], "rmp_br": [num(v, 2) for v in d["rmp_suav_br"]], # índice do município -> contexto do sinal (p = prioritário, c = capital, e = entorno de capital, t = polo) "sinal": { str(i): {"prioritário": "p", "capital": "c", "entorno de capital": "e", "polo de tratamento": "t"}[ctx] for i, ctx in enumerate(d["contexto"].fillna("")) if ctx }, } (MAPA / "dados.json").write_text(json.dumps(dados, ensure_ascii=False, separators=(",", ":"))) malha(BRUTOS / "malha_municipios.geojson", MAPA / "municipios.geojson", "cod") malha(BRUTOS / "malha_ufs.geojson", MAPA / "ufs.geojson", "uf") for arq in ("sinais.csv", "municipios_rmp.csv", "sensibilidade.csv", "parametros_suavizacao.csv"): if (RESULTADOS / arq).exists(): shutil.copy(RESULTADOS / arq, MAPA / arq) # código da análise, publicado junto com o site para quem quiser reproduzir codigo = MAPA.parent / "codigo" codigo.mkdir(exist_ok=True) for arq in ("config.py", "baixar.py", "preparar.py", "analisar.py", "sensibilidade.py", "gerar_mapa.py", "gerar_relatorio.py", "modelo_relatorio.html", "requirements.txt", "README.md"): shutil.copy(Path(__file__).resolve().parent / arq, codigo / arq) preview_svg("esofago", MAPA / "preview-esofago.svg") for arq in sorted(MAPA.iterdir()): print(f" {arq.name:24s} {arq.stat().st_size / 1e6:6.2f} MB") if __name__ == "__main__": main()