Online GeoPandas Compiler

Run GeoPandas code in your browser. Read shapefiles, build points from coordinates, reproject, join by location and map.

Python
import urllib.request

import geopandas
import matplotlib.pyplot as plt

# New York City's five boroughs, as a zipped shapefile
url = "https://raw.githubusercontent.com/geopandas/geodatasets/main/data_backup/nybb_16a.zip"
urllib.request.urlretrieve(url, "nybb.zip")
gdf = geopandas.read_file("zip://nybb.zip!nybb_16a/nybb.shp")

ax = gdf.plot(column="Shape_Area", cmap="viridis", legend=True, figsize=(8, 8))
ax.set_axis_off()
plt.tight_layout()
plt.show()

GeoPandas extends pandas to geographic data. A GeoDataFrame is a DataFrame with a geometry column of points, lines or polygons. GeoPandas reads and writes shapefiles and GeoJSON, converts between coordinate systems, measures areas and distances, and joins tables by location. People use it to map regions and to find which area each address falls in. This page is an online GeoPandas compiler: the code runs in your browser, so you can try it without installing anything. Run the example first, then paste any snippet below into a new cell to try it.

What the example does

urllib.request.urlretrieve() downloads a zipped shapefile of New York City's five boroughs and saves it as nybb.zip. geopandas.read_file() opens the shapefile inside it: the zip://nybb.zip!nybb_16a/nybb.shp path names the archive, then the file within it. The result, gdf, has one row per borough and a geometry column of polygons. gdf.plot(column="Shape_Area", cmap="viridis", legend=True) shades each borough by its area and adds a color bar. The file uses EPSG:2263, a New York projection measured in US survey feet, so Shape_Area is in square feet. Queens is the largest borough and Manhattan the smallest.

Make a GeoDataFrame from coordinates

points_from_xy() turns latitude and longitude columns into points. It takes x first, and x is longitude. crs="EPSG:4326" records that the numbers are degrees:

import geopandas
import matplotlib.pyplot as plt
import pandas as pd

cities = pd.DataFrame({
    "city": ["Seattle", "Denver", "Chicago", "Atlanta", "Boston"],
    "lat": [47.61, 39.74, 41.88, 33.75, 42.36],
    "lon": [-122.33, -104.99, -87.63, -84.39, -71.06],
})
gdf = geopandas.GeoDataFrame(
    cities, geometry=geopandas.points_from_xy(cities.lon, cities.lat), crs="EPSG:4326"
)
print(gdf)

ax = gdf.plot(markersize=40, color="crimson")
for x, y, name in zip(gdf.geometry.x, gdf.geometry.y, gdf.city):
    ax.annotate(name, (x, y), xytext=(4, 4), textcoords="offset points")
plt.show()

Reproject before you measure

A degree is not a fixed distance: one degree of longitude is about 111 km at the equator and 56 km at latitude 60°. Convert to a projected system with to_crs() before measuring. estimate_utm_crs() picks the UTM zone that covers your data, and its units are meters:

import geopandas
from shapely.geometry import Polygon

# Central Park's four corners, as (longitude, latitude)
corners = [(-73.9819, 40.7681), (-73.9580, 40.8003),
           (-73.9493, 40.7968), (-73.9730, 40.7644)]
park = geopandas.GeoSeries([Polygon(corners)], crs="EPSG:4326")
utm = park.estimate_utm_crs()
park_m = park.to_crs(utm)

print(utm.name)
print(f"Area: {park_m.area.iloc[0] / 1e6:.2f} km²")
print(f"Perimeter: {park_m.length.iloc[0] / 1000:.2f} km")

It picks UTM zone 18N and prints 3.47 km² and 9.91 km.

Join points to the areas they fall in

sjoin() joins two GeoDataFrames by location instead of by a key column, so each shop gets the zone it is in. how="left" keeps shop D, which is outside both zones, with NaN as its zone:

import geopandas
from shapely.geometry import Point, box

zones = geopandas.GeoDataFrame(
    {"zone": ["West", "East"]}, geometry=[box(0, 0, 5, 5), box(5, 0, 10, 5)]
)
shops = geopandas.GeoDataFrame(
    {"shop": ["A", "B", "C", "D"]},
    geometry=[Point(1, 1), Point(4, 3), Point(7, 2), Point(12, 1)],
)

joined = geopandas.sjoin(shops, zones, how="left", predicate="within")
print(joined[["shop", "zone"]])
print(joined["zone"].value_counts())

Put the data on a web map

folium.GeoJson() draws a GeoDataFrame on a Leaflet web map, and GeoJsonTooltip shows a column when the pointer is over a shape. The Folium example covers more:

import folium
import geopandas
from shapely.geometry import Polygon

corners = [(-73.9819, 40.7681), (-73.9580, 40.8003),
           (-73.9493, 40.7968), (-73.9730, 40.7644)]
park = geopandas.GeoDataFrame(
    {"name": ["Central Park"]}, geometry=[Polygon(corners)], crs="EPSG:4326"
)

m = folium.Map(location=[40.782, -73.966], zoom_start=13)
folium.GeoJson(park, tooltip=folium.GeoJsonTooltip(fields=["name"])).add_to(m)
m

Good to know

  • gdf.explore() raises an ImportError here. It needs mapclassify, whose current release requires pandas 2.3, and this Python environment has pandas 2.2.3. Use folium as above.
  • Measuring in EPSG:4326 does not fail: .area returns square degrees with a warning that the results "are likely incorrect".
  • For a zipped shapefile whose files sit in a folder, name the .shp inside it as the example does. The bare .zip path fails. To use your own file, click Mount folder in the sidebar's Data tab (Chrome or Edge on a computer) and choose the folder it is in. gdf.to_file("out.geojson", driver="GeoJSON") saves a copy.