Ecuador Geo-Visualization: Heatmap by Region

code
visualization
Author

Marco Aguirre

Published

July 26, 2025

This project presents an interactive choropleth map of Ecuador using the Folium library, which combines Python with Leaflet.js for dynamic geographic visualizations. The objective is to visually represent region-based intensity data — such as metrics from surveys, socioeconomic indicators, or other analytics — on a province-level map of Ecuador.

Features:

  • Loads and parses a GeoJSON file containing Ecuadorian provinces with standardized identifiers.
  • Dynamically maps a selected column of intensity values to color gradients using the matplotlib colormap.
  • Automatically normalizes data and assigns hex-based color codes to each region.
  • Allows interactive exploration with tooltips showing the name of each province.
  • Includes a color-coded legend and layer control.
import folium
import pandas as pd
import json
import matplotlib.cm as cm
import matplotlib.colors as mcolors
from branca.colormap import linear
import numpy as np

def draw_map(data, column):
    """
    Draws a chloropleth-style map of Ecuador using intensity values from a given column.

    Parameters:
    - data (DataFrame): A pandas DataFrame containing intensity values.
    - column (str): Name of the column in `data` to visualize.

    Returns:
    - folium.Map object with colored regions based on intensity values.
    """

    # Mapping from numeric province codes to Ecuador GeoJSON IDs
    id_dict = {
        1: "ECE", 2: "ECC", 3: "ECU", 4: "ECD", 5: "ECY", 6: "ECS",
        7: "ECZ", 8: "ECL", 9: "ECO", 10: "ECG", 11: "ECW", 12: "ECSE",
        13: "ECM", 14: "ECA", 15: "ECF", 16: "ECN", 17: "ECT", 18: "ECH",
        19: "ECB", 20: "ECI", 21: "ECX", 22: "ECR", 23: "ECP", 24: "ECSD"
    }

    # Create a DataFrame with IDs and attach intensity values
    df = pd.DataFrame(list(id_dict.items()), columns=["num", "id"])
    df["intensity"] = data[column]

    # Normalize the data and apply a colormap (e.g., 'hot')
    norm = mcolors.Normalize(vmin=data[column].min(), vmax=data[column].max())
    cmap = cm.get_cmap("hot")
    df["color"] = df["intensity"].apply(lambda x: mcolors.to_hex(cmap(norm(x))))

    # Dictionary to map province IDs to HEX colors
    color_dict = dict(zip(df["id"], df["color"]))

    # Load Ecuador's GeoJSON data
    with open("ecuador.json", "r", encoding="utf-8") as f:
        geo_json_data = json.load(f)

    # Initialize the base map centered on Ecuador
    m = folium.Map(
        location=[1.1869562532846696, -78.4783050193744],
        zoom_start=8,
        tiles="Cartodb Positron"
    )

    # Overlay GeoJSON layer with custom style and tooltip
    folium.GeoJson(
        geo_json_data,
        name="Intensity Heatmap",
        style_function=lambda feature: {
            "fillColor": color_dict.get(feature["properties"]["id"], "#808080"),  # Gray if no match
            "color": "black",
            "weight": 1,
            "dashArray": "5, 5",
            "fillOpacity": 0.8,
        },
        tooltip=folium.GeoJsonTooltip(
            fields=["name"],
            aliases=["Zone name:"]
        )
    ).add_to(m)

    # Add layer controls (useful if multiple layers are added)
    folium.LayerControl().add_to(m)

    return m

Create Synthetic Data for Plot


data = pd.DataFrame({
    "intensidad": np.random.uniform(0, 100, size=24)
})
draw_map(data, "intensidad")
<positron-console-cell-19>:35: MatplotlibDeprecationWarning: The get_cmap function was deprecated in Matplotlib 3.7 and will be removed in 3.11. Use ``matplotlib.colormaps[name]`` or ``matplotlib.colormaps.get_cmap()`` or ``pyplot.get_cmap()`` instead.
Make this Notebook Trusted to load map: File -> Trust Notebook