st.map y st.pydeck_chart para datos geoespaciales

Intermedio
Streamlit
Streamlit
Actualizado: 26/04/2026

st.map: mapa de puntos rápido

st.map es la forma más sencilla de visualizar datos con coordenadas geográficas en Streamlit. Con una sola línea de código genera un mapa interactivo (basado en deck.gl) donde cada fila del DataFrame se representa como un punto en el mapa. Requiere un DataFrame con columnas lat/latitude y lon/longitude:

import streamlit as st
import pandas as pd
import numpy as np

# Datos de sucursales bancarias en España
df_sucursales = pd.DataFrame({
    "lat": [40.416, 41.385, 39.470, 37.389, 43.263],
    "lon": [-3.703, 2.173, -0.376, -5.986, -2.935],
    "ciudad": ["Madrid", "Barcelona", "Valencia", "Sevilla", "Bilbao"],
    "clientes": [15420, 12340, 8760, 9120, 5430]
})

# Mapa básico
st.map(df_sucursales)

# Con zoom inicial y color personalizado
st.map(
    df_sucursales,
    latitude="lat",
    longitude="lon",
    zoom=5,
    color="#FF4B4B",
    size="clientes"  # Tamaño proporcional al número de clientes
)
flowchart TD
    A[DataFrame con lat lon] --> B{"Necesidad?"}
    B -->|Mapa simple| C[st.map color size opcional]
    B -->|Mapa avanzado| D[st.pydeck_chart con Deck]
    C --> E[deck.gl básico bajo el capot]
    D --> F[ScatterplotLayer puntos]
    D --> G[HexagonLayer agregaciones]
    D --> H[TextLayer etiquetas]
    D --> I[ArcLayer rutas origen destino]
    F --> J[ViewState lat lon zoom pitch]
    G --> J
    H --> J
    I --> J
    J --> K[Mapa interactivo Mapbox]
    E --> K
    K --> L[Dashboard geoespacial profesional]

Mapa interactivo con filtros

import streamlit as st
import pandas as pd
import numpy as np

# Generar datos de alquileres en Madrid
np.random.seed(42)
n = 200
df = pd.DataFrame({
    "lat": np.random.normal(40.416, 0.05, n),
    "lon": np.random.normal(-3.703, 0.07, n),
    "precio": np.random.randint(600, 2500, n),
    "habitaciones": np.random.choice([1, 2, 3, 4], n),
    "barrio": np.random.choice(["Salamanca", "Chamberí", "Centro", "Retiro", "Arganzuela"], n)
})

# Filtros en sidebar
with st.sidebar:
    st.header("Filtros")
    precio_max = st.slider("Precio máximo (€/mes)", 600, 2500, 1500, step=100)
    barrios = st.multiselect("Barrios", df["barrio"].unique(), default=list(df["barrio"].unique()))
    habitaciones = st.pills("Habitaciones", [1, 2, 3, 4], selection_mode="multi")

# Aplicar filtros
df_filtrado = df[
    (df["precio"] <= precio_max) &
    (df["barrio"].isin(barrios if barrios else df["barrio"].unique())) &
    (df["habitaciones"].isin(habitaciones if habitaciones else [1, 2, 3, 4]))
]

st.subheader(f"Mapa de alquileres en Madrid ({len(df_filtrado)} resultados)")
st.map(df_filtrado, color="#1F77B4", size="precio")

st.pydeck_chart: visualizaciones geoespaciales avanzadas

Para visualizaciones geoespaciales que requieren más control, PyDeck permite crear mapas con capas 3D, estilos personalizados, tooltips interactivos y múltiples tipos de representación sobre mapas base configurables. PyDeck es el wrapper Python de deck.gl, la biblioteca de visualización geoespacial de Uber:

import streamlit as st
import pydeck as pdk
import pandas as pd
import numpy as np

np.random.seed(42)
df = pd.DataFrame({
    "lat": np.random.normal(40.416, 0.05, 500),
    "lon": np.random.normal(-3.703, 0.07, 500),
    "peso": np.random.randint(1, 10, 500)
})

# ScatterplotLayer: puntos con radio y color configurables
scatter_layer = pdk.Layer(
    "ScatterplotLayer",
    data=df,
    get_position=["lon", "lat"],
    get_color=[255, 75, 75, 180],   # RGBA
    get_radius=200,                  # Radio en metros
    pickable=True
)

# Vista inicial del mapa
view_state = pdk.ViewState(
    latitude=40.416,
    longitude=-3.703,
    zoom=11,
    pitch=0
)

st.pydeck_chart(
    pdk.Deck(
        layers=[scatter_layer],
        initial_view_state=view_state,
        map_style="mapbox://styles/mapbox/light-v9",
        tooltip={"text": "Lat: {lat}\nLon: {lon}"}
    ),
    use_container_width=True
)

HexagonLayer: densidad de puntos en 3D

import streamlit as st
import pydeck as pdk
import pandas as pd
import numpy as np

np.random.seed(42)
df = pd.DataFrame({
    "lon": np.random.normal(-3.703, 0.06, 1000),
    "lat": np.random.normal(40.416, 0.04, 1000)
})

hex_layer = pdk.Layer(
    "HexagonLayer",
    data=df,
    get_position=["lon", "lat"],
    radius=200,
    elevation_scale=4,
    elevation_range=[0, 1000],
    pickable=True,
    extruded=True,      # Barras 3D
    coverage=1
)

st.pydeck_chart(
    pdk.Deck(
        layers=[hex_layer],
        initial_view_state=pdk.ViewState(
            latitude=40.416,
            longitude=-3.703,
            zoom=11,
            pitch=50,
            bearing=-27
        ),
        map_style="mapbox://styles/mapbox/dark-v9"
    )
)

Mapa coroplético con múltiples capas

import streamlit as st
import pydeck as pdk
import pandas as pd

# Datos de ciudades con etiquetas
ciudades = pd.DataFrame({
    "lat": [40.416, 41.385, 39.470, 37.389, 43.263],
    "lon": [-3.703, 2.173, -0.376, -5.986, -2.935],
    "nombre": ["Madrid", "Barcelona", "Valencia", "Sevilla", "Bilbao"],
    "poblacion": [3223334, 1636762, 789744, 684021, 345122]
})

# Capa de puntos escalados por población
scatter = pdk.Layer(
    "ScatterplotLayer",
    data=ciudades,
    get_position=["lon", "lat"],
    get_radius="poblacion / 20",
    get_fill_color=[255, 75, 75, 150],
    pickable=True
)

# Capa de texto con nombres
texto = pdk.Layer(
    "TextLayer",
    data=ciudades,
    get_position=["lon", "lat"],
    get_text="nombre",
    get_size=16,
    get_color=[0, 0, 0],
    get_alignment_baseline="'bottom'"
)

st.pydeck_chart(
    pdk.Deck(
        layers=[scatter, texto],
        initial_view_state=pdk.ViewState(latitude=40.0, longitude=-3.5, zoom=5),
        tooltip={"text": "{nombre}\nPoblación: {poblacion:,}"}
    )
)

st.pydeck_chart es la opción recomendada cuando se necesitan visualizaciones geoespaciales complejas: análisis de densidad, rutas, polígonos o datos en 3D. Para exploraciones rápidas y prototipos, st.map proporciona resultados aceptables con muy poco código.

PyDeck soporta múltiples estilos de mapa base: "mapbox://styles/mapbox/light-v9" para fondos claros, "mapbox://styles/mapbox/dark-v9" para fondos oscuros y "mapbox://styles/mapbox/satellite-v9" para imágenes satelitales. Para usar estilos de Mapbox es necesario configurar un token de API en st.secrets.

Contexto: cuándo usar cada función de mapas

Streamlit ofrece dos componentes principales para cartografía: st.map y st.pydeck_chart. La elección depende del nivel de complejidad de la visualización que necesites construir y del grado de personalización que quieras aplicar sobre el mapa base.

st.map está pensado como un atajo para exploraciones rápidas: cargas un DataFrame con columnas de coordenadas y obtienes un mapa interactivo sin escribir más código. Por debajo utiliza deck.gl con una capa de puntos preconfigurada, lo que limita las opciones de estilo pero garantiza que cualquier analista pueda ver sus datos geográficos en cuestión de segundos. Es ideal para auditorías, análisis exploratorios y dashboards internos donde la forma no es tan importante como la velocidad de iteración.

st.pydeck_chart, en cambio, expone toda la potencia de PyDeck. Con él puedes combinar múltiples capas (puntos, hexágonos, arcos, polígonos, textos), aplicar estilos de Mapbox, configurar tooltips HTML, controlar la cámara con pitch y bearing, y renderizar visualizaciones en 3D. Es la opción adecuada para productos orientados a usuarios finales o dashboards públicos donde la estética y el detalle son críticos.

Tabla de parámetros de st.map

| Parámetro | Tipo | Descripción | |-----------|------|-------------| | data | DataFrame | DataFrame con columnas de coordenadas | | latitude | str | Nombre de la columna de latitud (por defecto "lat"/"latitude") | | longitude | str | Nombre de la columna de longitud (por defecto "lon"/"longitude") | | color | str o columna | Color fijo ("#FF4B4B") o nombre de columna con valores RGBA | | size | float o columna | Radio fijo o columna numérica para escalar los puntos | | zoom | int | Nivel inicial de zoom (0-20) | | use_container_width | bool | Ajustar el ancho al contenedor padre |

Errores comunes y cómo evitarlos

No encuentra las columnas de coordenadas. Si tu DataFrame tiene columnas llamadas lng o longitud, st.map fallará porque solo reconoce lat/latitude y lon/longitude por defecto. La solución es renombrar o pasar los nombres explícitamente con los parámetros latitude y longitude.

Valores NaN en las coordenadas. Los registros con coordenadas nulas provocan que el mapa no se renderice correctamente o excluya puntos. Limpia el DataFrame con df.dropna(subset=["lat", "lon"]) antes de pasarlo al mapa.

Coordenadas invertidas. Es habitual confundir el orden de latitud y longitud en listas o tuplas. En PyDeck la convención es [lon, lat] mientras que muchas APIs devuelven [lat, lon]. Si ves tus puntos aparecer en el océano o en el hemisferio equivocado, revisa el orden.

Rendimiento con miles de puntos. Por encima de 10000 puntos, st.map se vuelve lento. En esos casos conviene usar HexagonLayer o GridLayer de PyDeck para agregar los datos antes de renderizarlos.

Mejores prácticas

  • Para datasets pequeños (menos de 1000 puntos), st.map suele ser suficiente y más rápido de implementar.
  • Cuando uses PyDeck con Mapbox, guarda el token en st.secrets["mapbox"]["token"] y nunca lo hardcodees en el script.
  • Combina capas de PyDeck para añadir contexto: por ejemplo, una ScatterplotLayer para los puntos y una TextLayer para etiquetarlos.
  • Aprovecha el parámetro pickable=True y los tooltips para ofrecer información detallada sin sobrecargar el mapa.
  • Cachea los datos geoespaciales con @st.cache_data cuando provengan de consultas SQL o APIs para evitar recargas innecesarias en cada interacción del usuario.
Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Streamlit es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de Streamlit

Explora más contenido relacionado con Streamlit y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

Crear mapas de puntos inmediatos con st.map a partir de columnas lat/lon. Personalizar el zoom, color y tamaño de puntos en st.map. Usar st.pydeck_chart para mapas avanzados con PyDeck y múltiples tipos de capas. Configurar ScatterplotLayer, HexagonLayer y TextLayer con pydeck. Combinar mapas con widgets de Streamlit para exploración geoespacial interactiva.