|
2 | 2 | from __future__ import annotations |
3 | 3 |
|
4 | 4 | import sys |
| 5 | +from typing import Any |
| 6 | + |
| 7 | +import pandas as pd |
5 | 8 |
|
6 | 9 | from common import add_indicators, ensure_dir, parse_args, read_dataset, save_json |
7 | 10 |
|
8 | 11 |
|
| 12 | +def safe_float(value: Any) -> float | None: |
| 13 | + return None if pd.isna(value) else float(value) |
| 14 | + |
| 15 | + |
| 16 | +def safe_int(value: Any) -> int | None: |
| 17 | + return None if pd.isna(value) else int(value) |
| 18 | + |
| 19 | + |
9 | 20 | def main() -> int: |
10 | | - parser = parse_args('Genera los archivos consumidos por el atlas interactivo.') |
| 21 | + parser = parse_args("Genera los archivos consumidos por el atlas interactivo.") |
11 | 22 | args = parser.parse_args() |
12 | 23 |
|
13 | | - df = add_indicators(read_dataset(args.input)).sort_values(['País', 'Año']).reset_index(drop=True) |
14 | | - out_dir = args.docs_dir / 'atlas' / 'data' |
| 24 | + df = ( |
| 25 | + add_indicators(read_dataset(args.input)) |
| 26 | + .sort_values(["País", "Año"]) |
| 27 | + .reset_index(drop=True) |
| 28 | + ) |
| 29 | + |
| 30 | + out_dir = args.docs_dir / "atlas" / "data" |
15 | 31 | ensure_dir(out_dir) |
16 | 32 |
|
17 | 33 | records = [] |
18 | 34 | for _, r in df.iterrows(): |
19 | | - records.append({ |
20 | | - 'country': r['País'], |
21 | | - 'iso3': r['ISO3'], |
22 | | - 'region': r['Región'], |
23 | | - 'year': int(r['Año']), |
24 | | - 'population_total_millions': float(r['Población_Total_Millones']), |
25 | | - 'age_groups_pct': { |
26 | | - '0_14': float(r['Pct_0_14']), '15_24': float(r['Pct_15_24']), '25_54': float(r['Pct_25_54']), |
27 | | - '55_64': float(r['Pct_55_64']), '65_plus': float(r['Pct_65_más']), |
| 35 | + record = { |
| 36 | + "country": r["País"], |
| 37 | + "year": int(r["Año"]), |
| 38 | + "population_total_millions": safe_float(r["Población_Total_Millones"]), |
| 39 | + "age_groups_pct": { |
| 40 | + "0_14": safe_float(r["Pct_0_14"]), |
| 41 | + "15_24": safe_float(r["Pct_15_24"]), |
| 42 | + "25_54": safe_float(r["Pct_25_54"]), |
| 43 | + "55_64": safe_float(r["Pct_55_64"]), |
| 44 | + "65_plus": safe_float(r["Pct_65_más"]), |
28 | 45 | }, |
29 | | - 'age_groups_thousands': { |
30 | | - '0_14': float(r['Pob_0_14_Miles']), '15_24': float(r['Pob_15_24_Miles']), '25_54': float(r['Pob_25_54_Miles']), |
31 | | - '55_64': float(r['Pob_55_64_Miles']), '65_plus': float(r['Pob_65_más_Miles']), |
| 46 | + "age_groups_thousands": { |
| 47 | + "0_14": safe_float(r["Pob_0_14_Miles"]), |
| 48 | + "15_24": safe_float(r["Pob_15_24_Miles"]), |
| 49 | + "25_54": safe_float(r["Pob_25_54_Miles"]), |
| 50 | + "55_64": safe_float(r["Pob_55_64_Miles"]), |
| 51 | + "65_plus": safe_float(r["Pob_65_más_Miles"]), |
32 | 52 | }, |
33 | | - 'indicators': { |
34 | | - 'aging_index': None if str(r['Indice_Envejecimiento']) == 'nan' else float(r['Indice_Envejecimiento']), |
35 | | - 'dependency_ratio_total': None if str(r['Razon_Dependencia_Total']) == 'nan' else float(r['Razon_Dependencia_Total']), |
36 | | - 'dependency_ratio_child': None if str(r['Razon_Dependencia_Infantil']) == 'nan' else float(r['Razon_Dependencia_Infantil']), |
37 | | - 'dependency_ratio_older': None if str(r['Razon_Dependencia_Mayores']) == 'nan' else float(r['Razon_Dependencia_Mayores']), |
38 | | - 'demographic_dividend_index': None if str(r['Indice_Bono_Demografico']) == 'nan' else float(r['Indice_Bono_Demografico']), |
39 | | - 'working_age_pct': float(r['Pct_Edad_Laboral']), |
40 | | - 'youth_pct': float(r['Pct_Joven_Total']), |
41 | | - 'working_age_thousands': float(r['Pob_Edad_Laboral_Miles']), |
42 | | - 'dependent_thousands': float(r['Pob_Dependiente_Miles']), |
43 | | - 'aging_change_vs_2000': None if str(r['Cambio_Envejecimiento_vs_2000']) == 'nan' else float(r['Cambio_Envejecimiento_vs_2000']), |
| 53 | + "indicators": { |
| 54 | + "aging_index": safe_float(r.get("Indice_Envejecimiento")), |
| 55 | + "youth_index": safe_float(r.get("Indice_Juventud")), |
| 56 | + "dependency_ratio_total": safe_float(r.get("Razon_Dependencia_Total")), |
| 57 | + "dependency_ratio_youth": safe_float(r.get("Razon_Dependencia_Juvenil")), |
| 58 | + "dependency_ratio_old_age": safe_float(r.get("Razon_Dependencia_Vejez")), |
| 59 | + "demographic_dividend_index": safe_float(r.get("Indice_Bono_Demografico")), |
| 60 | + "working_age_pct": safe_float(r.get("Pct_Edad_Laboral")), |
| 61 | + "youth_pct": safe_float(r.get("Pct_Joven_Total")), |
| 62 | + "older_pct": safe_float(r.get("Pct_65_más")), |
| 63 | + "working_age_thousands": safe_float(r.get("Pob_Edad_Laboral_Miles")), |
| 64 | + "dependent_thousands": safe_float(r.get("Pob_Dependiente_Miles")), |
| 65 | + "youth_to_older_ratio": safe_float(r.get("Relacion_Jovenes_Mayores")), |
| 66 | + "aging_change_vs_2000": safe_float(r.get("Cambio_Envejecimiento_vs_2000")), |
44 | 67 | }, |
45 | | - 'source': r['Fuente'], |
46 | | - }) |
| 68 | + "source": r["Fuente"], |
| 69 | + } |
| 70 | + |
| 71 | + # Solo incluir estas claves si existen en el dataset procesado |
| 72 | + if "ISO3" in df.columns: |
| 73 | + record["iso3"] = r["ISO3"] |
| 74 | + if "Región" in df.columns: |
| 75 | + record["region"] = r["Región"] |
| 76 | + |
| 77 | + records.append(record) |
47 | 78 |
|
48 | 79 | metadata = { |
49 | | - 'title': 'Atlas Demográfico Interactivo de América Latina', |
50 | | - 'author': 'Juan Moisés de la Serna', |
51 | | - 'record_count': int(len(df)), |
52 | | - 'country_count': int(df['País'].nunique()), |
53 | | - 'year_range': [int(df['Año'].min()), int(df['Año'].max())], |
54 | | - 'variables': list(df.columns), |
| 80 | + "title": "Atlas Demográfico Interactivo de América Latina", |
| 81 | + "author": "Juan Moisés de la Serna", |
| 82 | + "record_count": int(len(df)), |
| 83 | + "country_count": int(df["País"].nunique()), |
| 84 | + "year_range": [int(df["Año"].min()), int(df["Año"].max())], |
| 85 | + "years": sorted(int(y) for y in df["Año"].dropna().unique()), |
| 86 | + "countries": sorted(str(c) for c in df["País"].dropna().unique()), |
| 87 | + "variables": list(df.columns), |
| 88 | + "source_column": "Fuente", |
| 89 | + "dataset_description": ( |
| 90 | + "Dataset demográfico comparativo con población total, estructura " |
| 91 | + "por grupos de edad en porcentaje y población por grupos de edad " |
| 92 | + "en miles." |
| 93 | + ), |
55 | 94 | } |
56 | 95 |
|
57 | | - save_json(out_dir / 'atlas_data.json', {'metadata': metadata, 'records': records}) |
58 | | - save_json(out_dir / 'atlas_metadata.json', metadata) |
59 | | - df.to_csv(out_dir / 'atlas_data_with_indicators.csv', index=False, encoding='utf-8-sig') |
| 96 | + save_json(out_dir / "atlas_data.json", {"metadata": metadata, "records": records}) |
| 97 | + save_json(out_dir / "atlas_metadata.json", metadata) |
| 98 | + df.to_csv(out_dir / "atlas_data_with_indicators.csv", index=False, encoding="utf-8-sig") |
60 | 99 |
|
61 | 100 | print(f'OK: {out_dir / "atlas_data.json"}') |
62 | 101 | print(f'OK: {out_dir / "atlas_metadata.json"}') |
63 | 102 | print(f'OK: {out_dir / "atlas_data_with_indicators.csv"}') |
64 | 103 | return 0 |
65 | 104 |
|
66 | 105 |
|
67 | | -if __name__ == '__main__': |
| 106 | +if __name__ == "__main__": |
68 | 107 | try: |
69 | 108 | raise SystemExit(main()) |
70 | 109 | except Exception as exc: |
71 | | - print(f'ERROR: {exc}', file=sys.stderr) |
| 110 | + print(f"ERROR: {exc}", file=sys.stderr) |
72 | 111 | raise |
0 commit comments