A GeoDataFrame contains large coordinate numbers, but the HTML map needs points in the right place. Identify what the input coordinates mean before assigning or changing their coordinate reference system. Labeling projected meters as longitude and latitude does not convert them into degrees.
This original fictional exercise starts with two inspection points in Web Mercator meters. Point A is at x = 111319.490793, y = 0. Point B is at x = 222638.981587, y = 111325.142866. They are teaching coordinates, not real inspection locations or customer records. After conversion, they should be approximately longitude 1°, latitude 0°, and longitude 2°, latitude 1°.

Open the complete example · Download the full HTML source
Assign the source meaning, then transform the values
GeoPandas separates two operations. set_crs assigns coordinate reference information without transforming the geometry. to_crs transforms an active geometry column whose source reference is known.
For this supplied fixture, EPSG:3857 describes the input meters. EPSG:4326 describes the output geographic coordinates. The choice comes from the exercise's declared source format; it is not a guess based on how many digits appear in a coordinate.
from pathlib import Path
import geopandas as gpd
points = gpd.GeoDataFrame(
{"Site": ["Fictional A", "Fictional B"]},
geometry=gpd.points_from_xy(
[111319.490793, 222638.981587],
[0, 111325.142866],
),
crs="EPSG:3857",
)
geographic = points.to_crs("EPSG:4326")
print(geographic.geometry.x.tolist()) # approximately [1, 2]
print(geographic.geometry.y.tolist()) # approximately [0, 1]
map_view = geographic.explore(
tiles=None,
tooltip=["Site"],
popup=["Site"],
marker_type="circle_marker",
marker_kwds={"radius": 9},
height=420,
)
map_view.save(str(Path("inspection-map.html")))
Keep the original points object for comparison. In this example its first x coordinate remains about 111319.49, while the corresponding transformed x coordinate is about 1. Showing those two values beside the map makes the conversion inspectable.
Do not use set_crs("EPSG:4326", allow_override=True) as a substitute for this transformation. In the selected package, that operation changes the label while retaining the large source numbers. It is useful to correct reference metadata only when the replacement actually describes the existing coordinates. An unknown source reference needs investigation before a meaningful transformation can be chosen.
Check the point order at the data boundary
The GeoDataFrame uses x and y. The exported GeoJSON point coordinates are longitude first, latitude second. Leaflet's point interface displays a latitude/longitude pair. For Fictional B, those views should describe the same location: GeoJSON [2, 1] and a Leaflet position with latitude 1 and longitude 2, within the stated numerical tolerance.
The existing OpenLayers map guide handles degree-to-map conversion in browser code. This task happens earlier: interpret a Python geometry column correctly and inspect the geographic values exported by GeoDataFrame.explore. The Folium HTML guide covers saving and delivering the resulting map file.
Separate coordinate correctness from the background map
The explore API returns an interactive map built with Folium and Leaflet. This exercise deliberately uses no tile background. Its two circles establish that the generated geographic positions agree with the source conversion; they do not provide street context or evidence that a real-world address is correct.
Check both point labels and positions before handing over the export. Open each popup, zoom in and back out, and confirm the points remain associated with their original names. At phone width, check that the map has usable height and its explanation remains readable.
Keep the native export with the Python generator. A separate prepared reading copy may embed the required browser resources and explain the conversion beside the map. Identify that preparation clearly. A single HTML filename does not prove its scripts, styles, or map images are included in the file. Audit what the chosen export actually loads before promising offline delivery.