Introduction
To read a KML file (Keyhole Markup Language, commonly used with Google Earth) in Python, you can use several libraries depending on your needs. This guide covers reading, troubleshooting, and visualizing KML files using geopandas
, folium
, and alternative libraries like fastkml
and pykml
.
Generate Fake KML Files for Testing
To test your code without real KML files, you can create dummy files.
Simple KML File (Single Layer with Points)
Save this as simple.kml
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?xml version="1.0" encoding="UTF-8"?> <kml xmlns="http://www.opengis.net/kml/2.2"> <Document> <name>Simple KML Example</name> <Placemark> <name>Point A</name> <Point> <coordinates>-122.0822,37.4223,0</coordinates> </Point> </Placemark> <Placemark> <name>Point B</name> <Point> <coordinates>-122.0850,37.4230,0</coordinates> </Point> </Placemark> </Document> </kml> |
Multi-Layer KML File (Using Folders)
Save this as multi_layer.kml
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <?xml version="1.0" encoding="UTF-8"?> <kml xmlns="http://www.opengis.net/kml/2.2"> <Document> <name>Multi-Layer KML Example</name> <Folder> <name>Layer 1 - Red Points</name> <Placemark> <name>Red Point 1</name> <Point> <coordinates>-122.1,37.4,0</coordinates> </Point> </Placemark> </Folder> <Folder> <name>Layer 2 - Blue Points</name> <Placemark> <name>Blue Point 1</name> <Point> <coordinates>-122.2,37.5,0</coordinates> </Point> </Placemark> <Placemark> <name>Blue Point 2</name> <Point> <coordinates>-122.3,37.6,0</coordinates> </Point> </Placemark> </Folder> </Document> </kml> |
Reading KML Files with geopandas
First, ensure geopandas
is installed:
1 | pip install geopandas |
Read a Simple KML File
1 2 3 4 | import geopandas as gpd gdf = gpd.read_file("simple.kml", driver='KML') print(gdf.head()) |
Example Output
1 2 3 4 5 6 7 | Name description timestamp begin end altitudeMode tessellate extrude \ 0 Point A None NaT NaT NaT None -1 0 1 Point B None NaT NaT NaT None -1 0 visibility drawOrder icon geometry 0 -1 NaN None POINT Z (-122.0822 37.42229 0) 1 -1 NaN None POINT Z (-122.085 37.423 0) |
Read Specific Layers from a Multi-layer KML File
Python Code
1 2 3 4 5 6 7 | # List layers import fiona print(fiona.listlayers("multi_layer.kml")) # Read first layer gdf = gpd.read_file("multi_layer.kml", driver='KML', layer=0) print(gdf.head()) |
Example Output
1 2 3 4 5 | Name description timestamp begin end altitudeMode tessellate \ 0 Red Point 1 None NaT NaT NaT None -1 extrude visibility drawOrder icon geometry 0 0 -1 NaN None POINT Z (-122.1 37.4 0) |
Troubleshooting Common Errors
❌ IndexError: index 0 is out of bounds for axis 0 with size 0
If you get the error:
1 | IndexError: index 0 is out of bounds for axis 0 with size 0 |
It means that the KML file was successfully read, but the layer you tried to access contains no features — the file is valid, but empty for that specific layer.
Before accessing a specific layer, it's a good idea to inspect which layers exist and how many features they contain.
First, install Fiona: Fiona is a Python library for reading and writing spatial data formats like GeoPackage, Shapefile, and KML. It provides a simpler, Pythonic interface to GDAL for vector data, and supports reading from multi-layer formats (e.g., KML, GPKG, zipped datasets, cloud storage, etc.).
1 | pip install fiona |
Then use the following code to list the layers in your KML file:
1 2 3 4 5 | import fiona layers = fiona.listlayers("multi_layer.kml") print(f"Number of layers: {len(layers)}") print("Layer names:", layers) |
Example Output
1 2 | Number of layers: 2 Layer names: ['Layer 1 - Red Points', 'Layer 2 - Blue Points'] |
❌ DriverError: unsupported driver: 'KML'
Solution: Install GDAL with KML support.
Ubuntu/Debian:
1 | sudo apt-get install gdal-bin libgdal-dev |
macOS (Homebrew):
1 | brew install gdal |
Conda (Recommended):
1 | conda install -c conda-forge gdal fiona geopandas |
Then check supported drivers:
1 2 | import fiona print(fiona.supported_drivers) |
You should see 'KML': 'rw'
in the list.
❌ TypeError: Object of type Timestamp is not JSON serializable
Occurs when plotting with folium
.
Fix: Convert datetime columns to string:
Python Code
1 2 3 4 5 6 7 8 | import pandas as pd gdf = gdf.copy() for col in gdf.columns: if pd.api.types.is_datetime64_any_dtype(gdf[col]): gdf[col] = gdf[col].astype(str) gdf = gdf.applymap(lambda x: str(x) if isinstance(x, (pd.Timestamp, pd.Timedelta)) else x) |
Visualizing KML Files with folium
1. Install folium:
Bash
1 | pip install folium |
2. Display KML on an Interactive Map
Python Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import geopandas as gpd import folium # Load KML file gdf = gpd.read_file("simple.kml", driver='KML') # Center map center = gdf.geometry.iloc[0].centroid.coords[:][0][::-1] m = folium.Map(location=center, zoom_start=10) # Fix datetime issues gdf = gdf.applymap(lambda x: str(x) if isinstance(x, pd.Timestamp) else x) # Add GeoJSON layer folium.GeoJson(gdf).add_to(m) # Export map m.save("map_with_kml.html") |
Optional: Static Plot with GeoPandas
Python Code:
1 | gdf.plot() |
Note: This generates a static image, not interactive.
Alternatives to GeoPandas
fastkml
: Efficient and lightweight
Bash
1 | pip install fastkml |
Python Code:
1 2 3 4 5 6 7 8 9 10 11 12 | from fastkml import kml with open("simple.kml", "rt", encoding="utf-8") as f: doc = f.read() k = kml.KML() k.from_string(doc) for feature in k.features(): for placemark in feature.features(): print("Name:", placemark.name) print("Geometry:", placemark.geometry) |
pykml
: For detailed XML tree parsing
Bash
1 | pip install pykml |
Python Code:
1 2 3 4 5 6 7 8 | from pykml import parser with open("simple.kml") as f: root = parser.parse(f).getroot() for placemark in root.Document.Placemark: print(placemark.name) print(placemark.Point.coordinates) |
Summary
- Use
geopandas
for reading and analyzing KML geospatial data. - Use
folium
for interactive web maps. - Use
fastkml
orpykml
for lightweight parsing or full control. - Check your GDAL/KML support if you run into driver errors.