mrkeyoor.com_
Sat 08 Aug 21:01 UTC
PyPIDataupdated 08 Aug 2026

geopandas

GeoPandas brings vector geographic data into the pandas model. A GeoDataFrame is a DataFrame with an active geometry column, a coordinate reference system, file and database readers, spatial joins, overlays, projections, and plotting. Shapely performs geometry work, pyproj handles projections, and pyogrio handles most file I/O. It is the natural choice when analysis already looks like pandas and locations are points, lines, or polygons rather than raster pixels.

Verdict

Install GeoPandas when vector GIS work belongs naturally in a pandas workflow. Do not treat it as a raster tool, a distributed engine, or a substitute for understanding coordinate systems.

API stability4/5GeoSeries and GeoDataFrame have been the public center of the project for years, and familiar pandas methods remain available because both types subclass pandas objects. The current release requires modern pandas, Shapely, pyproj, and pyogrio versions, so environment upgrades can still expose behavior changes below GeoPandas even when the top-level method names stay familiar.
Docs5/5The project links a versioned documentation site with installation guidance, user guides, API reference, examples, and separate development documentation. The README clearly calls out Cartesian operations, CRS storage, optional plotting, the supported I/O layer, and difficult native dependencies, which are exactly the details that prevent plausible but wrong spatial analysis.
Maintenance5/5Version 1.1.4 was uploaded on June 26, 2026, and the repository was pushed on August 5, 2026. The project has open governance, NumFOCUS fiscal sponsorship, regular test automation, and many contributors. The GitHub count includes 433 open issues and pull requests, but that backlog sits alongside active work rather than an archived or disabled repository.
Ecosystem5/5GeoPandas connects directly to the mature pandas, Shapely, pyproj, and pyogrio ecosystem and supports formats understood by the underlying GDAL-backed reader. Optional packages cover maps, classification, Arrow, databases, and geocoding. Its 5,218 GitHub stars and central role in Python vector analysis make examples and compatible tooling easy to find.

Use it if

  • Your analysis combines ordinary pandas columns with point, line, or polygon geometry
  • You need spatial joins, overlays, clipping, dissolves, or coordinate transformations in a Python notebook or batch job
  • You exchange common GIS files or GeoParquet and want one DataFrame-oriented API
  • You want quick static maps through Matplotlib or interactive exploration without adopting a desktop GIS
Skip it if

Setup reality

A current wheel install is usually as simple as `pip install geopandas`, but the simple command hides a compiled geospatial stack. GeoPandas 1.1.4 requires Python 3.10 or newer plus pandas 2+, Shapely 2+, pyproj, and pyogrio. Wheels cover common platforms; uncommon architectures, source installs, or tightly pinned environments can expose GEOS, PROJ, and GDAL compatibility problems, which is why the project still recommends conda for difficult installations. Plotting is optional and needs Matplotlib; interactive `.explore()` work adds Folium, mapclassify, and xyzservices. Database I/O adds SQLAlchemy, a driver such as psycopg, and often GeoAlchemy2. The first analytical surprise is CRS rather than installation: loading a file may set a CRS, but constructing geometries often does not. `set_crs()` labels existing coordinates and does not transform them; `to_crs()` performs the transformation. Area, distance, buffering, overlay, and joins are Cartesian, so longitude and latitude data should normally be projected first. Large overlay and join operations can also create many rows and substantial memory pressure. Treat CRS checks, geometry validity, and output row counts as production validation, not notebook polish.

Patterns

Read selected columns from a vector fileread-vector-file

import geopandas as gpd

gdf = gpd.read_file(
    'data/parcels.gpkg',
    layer='parcels',
    columns=['parcel_id', 'owner', 'geometry'],
)
print(gdf.crs)

Check `crs` immediately. A missing or incorrectly labelled CRS makes later distance, area, and join results unreliable.

Create point geometry from longitude and latitudecreate-geodataframe

import pandas as pd
import geopandas as gpd

df = pd.DataFrame({'city': ['Oslo'], 'lon': [10.7522], 'lat': [59.9139]})
gdf = gpd.GeoDataFrame(
    df,
    geometry=gpd.points_from_xy(df.lon, df.lat),
    crs='EPSG:4326',
)

`points_from_xy` expects x then y, which means longitude then latitude for EPSG:4326.

Project geometries before metric calculationstransform-crs

projected = gdf.to_crs(gdf.estimate_utm_crs())
projected['area_m2'] = projected.geometry.area
projected['buffer'] = projected.geometry.buffer(250)

`set_crs()` only labels coordinates. Use `to_crs()` to change them, and avoid area or buffer calculations directly in longitude and latitude.

Attach polygon attributes to pointsspatial-join

joined = gpd.sjoin(
    points,
    districts[['district_id', 'geometry']],
    how='left',
    predicate='within',
)
joined = joined.drop(columns='index_right')

Both inputs must use compatible coordinate systems. A point on a polygon boundary is not `within`; choose `intersects` if boundary matches count.

Find the nearest feature with a distance capnearest-join

result = gpd.sjoin_nearest(
    addresses.to_crs('EPSG:3857'),
    stations.to_crs('EPSG:3857'),
    how='left',
    max_distance=5000,
    distance_col='distance_m',
)

Nearest distances are Cartesian. Project both frames first, and use a suitable local CRS when Web Mercator distortion is unacceptable.

Clip features to an area of interestclip-features

roads_in_city = gpd.clip(roads.to_crs(city.crs), city)
roads_in_city = roads_in_city.explode(index_parts=False).reset_index(drop=True)

Clipping can change geometry types or produce multipart results, so inspect validity and types before writing a strict output format.

Intersect two polygon layersoverlay-layers

zones = zones.to_crs(parcels.crs)
intersections = gpd.overlay(
    parcels[['parcel_id', 'geometry']],
    zones[['zone', 'geometry']],
    how='intersection',
    keep_geom_type=True,
)

Overlay may multiply rows when one feature meets several features, and invalid polygons can cause surprising fragments.

Merge features by a grouping columndissolve-polygons

regions = counties.dissolve(
    by='region',
    aggfunc={'population': 'sum', 'income': 'mean'},
    as_index=False,
)

Dissolve unions geometry as well as aggregating attributes; choose aggregation functions explicitly for every retained non-geometry column.

Detect and repair invalid geometryrepair-geometry

invalid = gdf.loc[~gdf.geometry.is_valid]
print(invalid[['geometry']])

gdf.loc[~gdf.geometry.is_valid, 'geometry'] = (
    gdf.loc[~gdf.geometry.is_valid, 'geometry'].make_valid()
)

Repairs can change a Polygon into a MultiPolygon or GeometryCollection. Validate the output type before relying on a downstream schema.

Write GeoParquet for efficient reusewrite-geoparquet

gdf.to_parquet(
    'output/parcels.parquet',
    index=False,
    compression='zstd',
)
round_trip = gpd.read_parquet('output/parcels.parquet')

Parquet support requires PyArrow. GeoParquet preserves geometry metadata better than exporting coordinates as ordinary table columns.

Read a spatial SQL queryquery-postgis

from sqlalchemy import create_engine, text

engine = create_engine('postgresql+psycopg://user:password@host/dbname')
sql = text('SELECT id, name, geom FROM places WHERE region_id = :region')
gdf = gpd.read_postgis(sql, engine, geom_col='geom', params={'region': 7})

Database support needs SQLAlchemy and a matching driver. Keep credentials outside source code and filter in SQL to avoid loading an entire table.

Make a classified choroplethplot-map

ax = districts.plot(
    column='population',
    scheme='quantiles',
    k=5,
    legend=True,
    missing_kwds={'color': 'lightgrey'},
)
ax.set_axis_off()

Static plotting needs Matplotlib, and classification schemes such as `quantiles` need mapclassify.

Alternatives

PackageRegistryPick it when
shapelyPyPIYou only need geometry creation and predicates without pandas tables or GIS file handling
pyogrioPyPIYou mainly need fast vector file I/O and can work with Arrow, NumPy, or a thinner data layer
duckdbPyPIYou want SQL, a spatial extension, and larger-than-memory query execution instead of eager DataFrames