Turn any GeoJSON, GeoPackage, GeoParquet or Shapefile into a standalone, self-contained interactive Leaflet map — one command, one HTML file.
geojson-to-map reads any vector dataset GeoPandas can open and writes a single, portable HTML file: an interactive Folium/Leaflet map with sensible styling, graduated or categorical coloring, a floating legend, a layer control, attribute popups and tooltips, and auto-fitted bounds. Open it in a browser, email it, or drop it on any static host — there is no server and no build step.
Maintained by python-geospatial.com, a knowledge base for the modern Python geospatial stack.
Getting data onto a web map usually means hand-writing Leaflet, wiring up a color scale, and fiddling with popups. geojson-to-map collapses that into one command while keeping the important things correct: geometry-aware styling, real classification schemes (quantiles, equal interval, Fisher-Jenks / natural breaks), and disciplined CRS handling that reprojects your data to EPSG:4326 and refuses to guess when the CRS is missing.
Not published to PyPI — install straight from the repository:
pip install "git+https://github.com/python-geospatial/geojson-to-map.git"Or clone and install in editable mode:
git clone https://github.com/python-geospatial/geojson-to-map.git
cd geojson-to-map
pip install -e ".[dev]"The mapclassify-backed schemes are optional; install them with the classify extra (otherwise a NumPy quantile/equal-interval fallback is used automatically):
pip install -e ".[classify]"geojson-to-map parcels.geojson -o parcels_map.html \
--color-by assessed_value --scheme quantiles -k 6 --tiles "CartoDB positron"Example output:
✓ Wrote parcels_map.html
Features : 1843 (polygon)
Bounds : lon -71.19124 → -70.98661, lat 42.22791 → 42.39655 (EPSG:4326)
Colored : by assessed_value (quantiles, k=6, viridis)
Common options:
| Option | Description |
|---|---|
-o, --output |
Output HTML path (defaults to <input>_map.html) |
--color-by |
Attribute column to color by (numeric → choropleth, text → categorical) |
--scheme |
quantiles, equal_interval, fisher_jenks, or natural_breaks |
-k |
Number of classes |
--cmap |
Colormap name (e.g. viridis, YlOrRd, Blues) |
--tiles |
Basemap tiles (e.g. OpenStreetMap, CartoDB positron) |
--title |
Optional title banner on the map |
--popup-fields / --tooltip-fields |
Comma-separated attribute fields |
--open / --no-open |
Open the finished map in your browser |
import geopandas as gpd
from geojson_to_map import render_map, write_map
# Straight from a file to an HTML map:
write_map("floodplain_boundary.gpkg", "flood_map.html",
color_by="risk_zone", cmap="YlOrRd")
# Or build a folium.Map from an in-memory GeoDataFrame:
parcels = gpd.read_file("parcels.geojson")
fmap = render_map(parcels, color_by="assessed_value", scheme="quantiles", k=6)
fmap.save("parcels_map.html")- Reads what GeoPandas reads — GeoJSON, GeoPackage, GeoParquet, Shapefile, and more.
- Geometry-aware styling — points become circle markers, lines become weighted strokes, polygons become filled shapes.
- Graduated and categorical coloring — numeric columns are classified (quantiles / equal interval / Fisher-Jenks / natural breaks) via
mapclassifywhen available, with a NumPy fallback; text columns get distinct qualitative colors. - A real legend — a floating HTML legend describing each class or category, including a "No data" swatch when values are missing.
- Popups, tooltips, layer control, auto-fit bounds — sensible defaults drawn from your first few attribute columns.
- Careful CRS handling — reprojects to EPSG:4326 for Leaflet and raises a clear, actionable error when the input CRS is undefined instead of misplacing your features.
- Truly standalone output — one self-contained HTML file, no server required.
The input is read with GeoPandas and reprojected to EPSG:4326 with .to_crs(4326). If the CRS is missing, geojson-to-map stops and tells you how to set it — assigning the wrong CRS silently moves every feature, so it never guesses. Features are split by geometry type and added to Folium layers with a per-feature style_function (or CircleMarkers for points). When --color-by is given, the column is classified and mapped to colors sampled from the chosen colormap, and a matching legend is attached. Bounds are fit to the data extent and a layer control is added before the map is serialized to a single HTML document.
Deep dives on the techniques behind this tool, from python-geospatial.com:
- Interactive Maps with Folium
- Folium Choropleth from a GeoDataFrame
- Shapefile & GeoJSON parsing
- Serving GeoJSON to MapLibre GL JS
- Web mapping & interactive visualization hub
git clone https://github.com/python-geospatial/geojson-to-map.git
cd geojson-to-map
pip install -e ".[dev,classify]"
ruff check .
pytestThe test suite builds tiny geometries in-code and runs entirely offline — no network access and no external fixtures.
MIT © 2026 python-geospatial.com