GeoPandas para iniciantes: tudo o que você precisa saber em 1 hora

Putz, eu lembro da primeira vez que abri um Jupyter Notebook pra rodar GeoPandas. Vinha de anos de QGIS, sabia o que era um shapefile, sabia o que era CRS, mas tava perdido na hora de transformar isso em código. Demorei semanas pra fazer o que hoje eu faço em 5 linhas.

Esse tutorial é o que eu queria ter lido naquela época. Em uma hora de leitura (com você executando os blocos de código), você vai sair fazendo análise espacial de verdade em Python. Sou Leonardo Marques, fundador do Clube do GIS, engenheiro ambiental e doutor em saneamento ambiental. Já formei mais de 10 mil profissionais em geoprocessamento desde 2014, e GeoPandas é uma das primeiras coisas que ensino em Python pra quem vem do QGIS.

Vamos do zero: instalação, GeoDataFrame, CRS, spatial join, buffer, dissolve e exportação. Tudo com dataset que você consegue rodar agora, sem baixar nada.

O que é GeoPandas e por que aprender

GeoPandas é uma biblioteca Python que estende o pandas pra trabalhar com dados geoespaciais. Se você já mexeu com pandas (DataFrame, Series, groupby), GeoPandas é a mesma coisa, só que cada linha tem uma coluna geometry que guarda um ponto, linha ou polígono.

Por baixo do capô, GeoPandas usa Shapely (geometrias), Fiona/Pyogrio (leitura de arquivo) e PyProj (sistemas de coordenadas). Você não precisa conhecer essas dependências pra começar, mas é bom saber que existem porque uma hora você vai precisar mexer direto com elas.

Por que aprender GeoPandas em vez de continuar só no QGIS:

  1. Reprodutibilidade. Um script de 30 linhas substitui 50 cliques no QGIS, e você roda de novo amanhã sem refazer nada.
  2. Escala. QGIS engasga em shapefiles grandes. GeoPandas processa milhões de feições sem suar (ainda mais com Pyogrio ou GeoArrow).
  3. Integração. Você plugga GeoPandas em pipelines de dados, machine learning, dashboards web. QGIS isolado não faz isso.
  4. Mercado. Vagas de “analista de geoprocessamento Python” pagam bem mais que vagas só de QGIS. É realidade.
import geopandas as gpd
print(gpd.__version__)

Se rodou, você tá pronto pra próxima seção. Se não rodou, vamos instalar.

Por que importa: GeoPandas é a porta de entrada pra todo o ecossistema GIS Python. Domina ele e o resto (Rasterio, Folium, PySAL) vem natural.

Instalando GeoPandas

A instalação é o ponto onde 70% das pessoas desistem. Não desiste agora porque a solução é simples: use conda (especificamente Miniconda ou Mamba). Pip funciona, mas no Windows costuma travar nas dependências GDAL e Fiona.

Caminho recomendado (conda, qualquer SO):

# cria ambiente isolado
conda create -n gis python=3.11
conda activate gis

# instala do canal conda-forge (importante!)
conda install -c conda-forge geopandas

Caminho alternativo (pip, se você sabe o que tá fazendo):

python -m venv .venv
# Windows
.venv\Scripts\activate
# Linux/Mac
source .venv/bin/activate

pip install geopandas pyogrio

Dica pra Windows: se der erro de DLL ao importar, é quase sempre conflito de GDAL. Apaga o ambiente e cria de novo só com conda-forge, sem misturar canais. Se você tem QGIS instalado, NÃO use o Python do QGIS pra rodar GeoPandas, cria um ambiente separado.

Pra confirmar que tá tudo OK:

import geopandas as gpd
import shapely
import fiona

print("GeoPandas:", gpd.__version__)
print("Shapely:", shapely.__version__)
print("Fiona:", fiona.__version__)

Por que importa: ambiente quebrado é a causa número 1 de frustração com Python GIS. Resolve isso uma vez, com conda, e nunca mais pensa nisso.

Lendo um shapefile e explorando o GeoDataFrame

Vou usar um dataset que vem com o GeoPandas pra você não precisar baixar nada. É o naturalearth_lowres, que tem polígonos de todos os países do mundo com população e PIB.

import geopandas as gpd

# atenção: a partir do GeoPandas 1.0 esse dataset foi removido,
# então vamos baixar direto da fonte oficial
url = "https://naciscdn.org/naturalearth/110m/cultural/ne_110m_admin_0_countries.zip"
mundo = gpd.read_file(url)

print(type(mundo))           # GeoDataFrame
print(mundo.shape)           # (177, várias colunas)
print(mundo.columns.tolist())
mundo.head()

Repara que mundo é um GeoDataFrame, igual a um DataFrame do pandas, só que com a coluna geometry. Você pode filtrar, agrupar, fazer tudo que faz com pandas:

# filtra só a América do Sul
america_sul = mundo[mundo["CONTINENT"] == "South America"]
print(america_sul[["NAME", "POP_EST"]].sort_values("POP_EST", ascending=False))

# plot rápido
america_sul.plot(figsize=(8, 8), edgecolor="black", color="lightblue")

A coluna geometry é especial. Cada célula é um objeto Shapely (Polygon, MultiPolygon, Point, etc.). Você pode acessar atributos geométricos direto:

brasil = mundo[mundo["NAME"] == "Brazil"]
print(brasil.geometry.iloc[0].geom_type)  # MultiPolygon
print(brasil.geometry.iloc[0].bounds)     # (xmin, ymin, xmax, ymax)

Por que importa: se você sabe pandas, você já sabe 80% do GeoPandas. A coluna geometry é o que muda, todo o resto é o mesmo workflow.

Sistemas de coordenadas (CRS) em GeoPandas

CRS é onde mais gente trava. A regra simples: todo GeoDataFrame tem um CRS (ou deveria ter), e você precisa saber qual é antes de fazer qualquer cálculo de área ou distância.

print(mundo.crs)
# EPSG:4326 (WGS 84, lat/lon em graus)

EPSG:4326 é o padrão GPS, latitude e longitude em graus. Problema: você não calcula área em graus quadrados. Pra área e distância, reprojeta pra um CRS métrico.

No Brasil, os CRS mais usados:

  • EPSG:4674 (SIRGAS 2000), padrão IBGE, geográfico em graus
  • EPSG:31983 (SIRGAS 2000 / UTM zona 23S), métrico, cobre boa parte do Sudeste e Centro-Oeste
  • EPSG:5880 (SIRGAS 2000 / Brazil Polyconic), métrico, cobre o Brasil inteiro com distorção aceitável pra mapas nacionais
# reprojeta pra um CRS métrico (Web Mercator pra exemplo global)
mundo_metrico = mundo.to_crs(epsg=3857)
print(mundo_metrico.crs)

# pra dados no Brasil, prefira:
# brasil_metrico = brasil.to_crs(epsg=5880)

Se um GeoDataFrame veio sem CRS definido (acontece muito com CSV de coordenadas), você define com .set_crs:

# define o CRS sem reprojetar (use quando você SABE qual é o CRS original)
gdf = gdf.set_crs(epsg=4326)

# reprojeta de um CRS pra outro (use quando quer mudar de sistema)
gdf = gdf.to_crs(epsg=31983)

Por que importa: 90% dos erros silenciosos em análise espacial vêm de CRS errado. Calcular distância em graus dá número sem sentido. Sempre confirma o CRS antes de medir qualquer coisa.

Calculando área, perímetro e geometria

Com o CRS métrico definido, área e perímetro saem na hora. Atenção: as unidades dependem do CRS. Em EPSG:5880 são metros, então .area retorna metros quadrados.

brasil_5880 = brasil.to_crs(epsg=5880)

# área em km²
area_km2 = brasil_5880.geometry.area / 1_000_000
print(f"Área do Brasil: {area_km2.iloc[0]:,.0f} km²")

# perímetro em km
perimetro_km = brasil_5880.geometry.length / 1_000
print(f"Perímetro: {perimetro_km.iloc[0]:,.0f} km")

# centroide (ponto central)
centroide = brasil_5880.geometry.centroid
print(centroide.iloc[0])

Outras propriedades úteis:

# bounding box (xmin, ymin, xmax, ymax)
print(brasil_5880.total_bounds)

# convex hull (envoltória convexa)
hull = brasil_5880.geometry.convex_hull

# representative point (ponto garantidamente DENTRO do polígono)
rep_point = brasil_5880.geometry.representative_point()

Diferença chata mas importante: centroid pode cair FORA do polígono se ele for em formato de C. Pra rotular feições no mapa, use representative_point().

Por que importa: essas operações são a base de qualquer relatório de geoprocessamento. Se você gerou tabelas no QGIS clicando em “calcular geometria”, agora você faz a mesma coisa em uma linha de código.

Spatial join: o SQL do mundo geo

Spatial join é onde GeoPandas brilha. É o equivalente espacial do JOIN do SQL: você cruza dois datasets pela relação geométrica entre eles (“este ponto está dentro deste polígono?”, “este polígono toca este outro?”).

Cenário real: você tem uma tabela de estabelecimentos com lat/lon, e precisa saber em qual município cada um cai.

import geopandas as gpd
from shapely.geometry import Point
import pandas as pd

# 1) cria pontos fictícios de estabelecimentos
dados = pd.DataFrame({
    "nome": ["Posto A", "Fábrica B", "Mercado C"],
    "lat": [-15.78, -23.55, -3.10],
    "lon": [-47.93, -46.63, -60.02],
})
geometria = [Point(xy) for xy in zip(dados["lon"], dados["lat"])]
estabelecimentos = gpd.GeoDataFrame(dados, geometry=geometria, crs="EPSG:4326")

# 2) carrega polígonos (no exemplo, países; na vida real, municípios IBGE)
mundo = gpd.read_file(
    "https://naciscdn.org/naturalearth/110m/cultural/ne_110m_admin_0_countries.zip"
)

# 3) spatial join: pra cada ponto, qual polígono o contém
resultado = gpd.sjoin(
    estabelecimentos,
    mundo[["NAME", "CONTINENT", "geometry"]],
    how="left",
    predicate="within",
)

print(resultado[["nome", "NAME", "CONTINENT"]])

O argumento predicate define a relação espacial. Os mais comuns:

  • intersects (qualquer interseção)
  • within (totalmente dentro)
  • contains (contém)
  • touches (encosta na borda)
  • crosses (cruza)

Por que importa: a tarefa “qual município cada CNPJ está” é o pedido número 1 que recebo de aluno trabalhando em prefeitura, vigilância sanitária, secretaria de meio ambiente. Spatial join resolve em 3 linhas o que no Excel seria impossível.

Buffer, intersect, dissolve em GeoPandas

Trio essencial: buffer cria zonas de influência, overlay cruza polígonos com polígonos, dissolve agrega.

Buffer (zona de influência ao redor de uma feição):

# atenção: buffer SÓ FAZ SENTIDO em CRS métrico
estabelecimentos_metrico = estabelecimentos.to_crs(epsg=5880)

# buffer de 5 km
estabelecimentos_metrico["buffer_5km"] = estabelecimentos_metrico.geometry.buffer(5000)

# transforma a coluna buffer em geometria ativa
buffers = estabelecimentos_metrico.set_geometry("buffer_5km")

Overlay (operação entre dois GeoDataFrames):

# imagina que você tem APP (Áreas de Preservação Permanente) e propriedades rurais
# e quer saber a sobreposição
sobreposicao = gpd.overlay(propriedades, app, how="intersection")

# how aceita: 'intersection', 'union', 'difference', 'symmetric_difference', 'identity'

Dissolve (agrupar feições por atributo):

# agrupa países por continente, somando população
continentes = mundo.dissolve(by="CONTINENT", aggfunc={"POP_EST": "sum"})
print(continentes[["POP_EST"]].sort_values("POP_EST", ascending=False))

dissolve é o equivalente do groupby do pandas, mas ele também une as geometrias do grupo num polígono só.

Por que importa: buffer + overlay + dissolve resolvem a maioria dos problemas de análise ambiental e de planejamento territorial. Sobreposição de propriedades em UC, áreas de risco perto de escolas, dissolução de glebas por proprietário, tudo cai aqui.

Plotagem rápida com matplotlib

GeoPandas tem .plot() direto, que é matplotlib por baixo. Pra mapas exploratórios é mais que suficiente.

import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(12, 8))

# mapa coroplético: cor por valor
mundo.plot(
    column="POP_EST",
    cmap="OrRd",
    legend=True,
    legend_kwds={"label": "População estimada", "orientation": "horizontal"},
    edgecolor="grey",
    linewidth=0.3,
    ax=ax,
)

ax.set_title("População mundial estimada", fontsize=14)
ax.set_axis_off()
plt.tight_layout()
plt.show()

Sobrepor camadas é só passar o mesmo ax:

fig, ax = plt.subplots(figsize=(10, 10))
mundo.plot(ax=ax, color="lightgrey", edgecolor="white")
estabelecimentos.plot(ax=ax, color="red", markersize=50)
plt.show()

Pra mapas web interativos, depois você pula pra Folium ou ipyleaflet. Mas pro dia a dia de relatório técnico, matplotlib resolve.

Por que importa: mapa exploratório rápido é o que separa quem faz análise de quem só faz figura bonita. .plot() deixa você ver o dado em segundos.

Exportando: shapefile, GeoPackage, GeoJSON

Depois de processar, você exporta. O método é sempre .to_file(), o que muda é a extensão e o driver.

# shapefile (legado, ainda usado, mas tem limites: nomes de campo até 10 chars)
brasil_5880.to_file("brasil.shp")

# GeoPackage (RECOMENDADO: arquivo único, sem limite de nome, suporta múltiplas camadas)
brasil_5880.to_file("dados.gpkg", layer="brasil", driver="GPKG")

# GeoJSON (ótimo pra web, leve, legível)
brasil.to_file("brasil.geojson", driver="GeoJSON")

# CSV com WKT (quando você precisa abrir no Excel)
brasil["geometry_wkt"] = brasil.geometry.to_wkt()
brasil.drop(columns="geometry").to_csv("brasil.csv", index=False)

Recomendação forte: abandone shapefile sempre que possível e use GeoPackage. Shapefile é da década de 90, tem limite de tamanho (2 GB), limite de caracteres em nome de coluna (10) e gera 4 arquivos por dataset. GeoPackage é um SQLite por baixo, arquivo único, e o QGIS abre nativamente.

Por que importa: o formato que você escolhe definir hoje vai te assombrar amanhã quando seu colega abrir o arquivo. GeoPackage evita 90% das dores de cabeça.

Como dar o próximo passo

Se você leu até aqui, executou os blocos e o código rodou, parabéns: você já sabe mais GeoPandas que 70% dos profissionais que botam “Python” no LinkedIn. Mas ler tutorial é diferente de fazer projeto de verdade, com dado sujo, com requisito mudando, com prazo apertado.

No Descomplica Geo-Python, eu te levo do GeoPandas básico até pipelines completos de geoprocessamento. São 74 aulas, 40 horas, com projetos reais que você consegue colocar no portfólio. Se você já fez QGIS e sabe Python básico, esse curso é pra ontem.

Ver detalhes do Descomplica Geo-Python

Perguntas frequentes

Preciso saber Python pra começar com GeoPandas?

Sim, mas só o básico: variáveis, listas, dicionários, loops, importar bibliotecas e usar pandas. Se você nunca programou, faz primeiro o Mini-Curso Introdutório Python GIS, que prepara o terreno em poucas horas.

GeoPandas substitui o QGIS?

Não substitui, complementa. QGIS continua sendo melhor pra exploração visual, edição manual de feições e cartografia final. GeoPandas é melhor pra automação, repetição e processamento em lote. Profissional bom usa os dois.

Qual a diferença entre GeoPandas e PyQGIS?

GeoPandas é uma biblioteca Python independente, roda em qualquer ambiente Python. PyQGIS é a API Python do QGIS, só roda dentro do QGIS (ou com configuração específica). GeoPandas é mais leve e portável, PyQGIS te dá acesso a todas as ferramentas do QGIS.

Importante dizer também que há uma solução para quem não tem tempo a perder e quer produzir mapas profissionais em pouquíssimo tempo

Eu montei um curso completo de QGIS que vai te levar do zero a mapas profissionais em 1 a 2 semanas, com suporte a dúvidas para te ajudar sempre que precisar: Curso completo de QGIS.

Espero ter te ajudado e aberto um novo leque de possibilidades!

Muito sucesso na jornada!

Gostou do conteúdo? Compartilhe nos botões abaixo!
WhatsApp
Facebook
Twitter
LinkedIn
Pinterest
Foto de Leonardo Marques

Leonardo Marques

Leonardo Marques é engenheiro ambiental e doutor, com atuação focada em Sistemas de Informação Geográfica (SIG/GIS), geoprocessamento, cartografia digital e sensoriamento remoto. É fundador e principal instrutor do Clube do GIS — a maior plataforma de ensino de geotecnologias do Brasil, com mais de 10.000 alunos formados em cursos de QGIS, ArcGIS, Python GIS, PostGIS, drones e análise espacial. Atua também como consultor e instrutor corporativo para empresas dos setores de agronegócio, meio ambiente, engenharia e planejamento urbano. Áreas de especialidade: QGIS avançado, análise multicritério, mapeamento aéreo com drones, Python para geoprocessamento e banco de dados espacial PostGIS.
Você também pode se interessar por estes posts…