Adam Surette

← Back to all projects

Published on 2024-11-10 23:49 by Adam Surette

Map

Why the map was made

This project was a private commission from a traveling companion who wanted to create an interactive map to share the highlights of their road trip with friends and family. I developed the map using Python and the Folium library, which allowed me to integrate geospatial data and create a visually engaging representation of their journey. The map provides an interactive experience where users can explore specific locations visited during the trip, with markers and custom descriptions for each stop.

How the map was made

The client shared their Google Earth Pro KMZ and asked for it to be made into soething interactive online. I converted the file to XML and wrote code using python to parse it, extract the data, and build a folium map with it.

import folium
from datetime import datetime
import xml.etree.ElementTree as ET
import os

# File path to the XML file
xml_file_path = '/.../.../.../.../RoadTrip.xml'

# Check if the XML file exists
if not os.path.exists(xml_file_path):
    raise FileNotFoundError(f"The file {xml_file_path} does not exist.")

# Parse the XML file (Use Element Tree Parse)
tree = ET.parse(xml_file_path)
root = tree.getroot()

# Initialize an empty list to store the data
data = []


# Setup of names= YEARMONTHDAY Descrription of location and activity
# Example: <name>20240213 Long hike at Hocking Hills State Park</name>
# Namespace handling
namespace = {'ns': 'http://www.opengis.net/kml/2.2'}  # Adjust the namespace according to your XML

# Extract data from the XML file (assume the XML structure is similar to KML)
for placemark in root.findall('.//ns:Placemark', namespace):
    # Extract coordinates (assuming XML structure has a 'coordinates' tag)
    coordinates = placemark.find('.//ns:coordinates', namespace)
    if coordinates is not None:
        lon, lat, _ = map(float, coordinates.text.split(','))
    
    # Extract name and description
    name_field = placemark.find('ns:name', namespace).text if placemark.find('ns:name', namespace) is not None else 'Unnamed'
    description = placemark.find('ns:description', namespace).text if placemark.find('ns:description', namespace) is not None else 'No Description'

    # Split the 'Name' field into date and description
    try:
        date_str, description = name_field.split(' ', 1)
        # Convert date from YYYYMMDD to 'YYYY-MM-DD' format
        date = datetime.strptime(date_str, '%Y%m%d').strftime('%Y-%m-%d')
    except ValueError:
        # Handle cases where 'Name' doesn't contain a space
        date = None
        description = name_field

    # Append the parsed data to the list
    data.append({
        'lat': lat,
        'lon': lon,
        'date': date,
        'description': description.strip()  # Strip any extra spaces
    })

# Sort data by date (exclude entries without a valid date)
data = [entry for entry in data if entry['date'] is not None]
data.sort(key=lambda x: datetime.strptime(x['date'], '%Y-%m-%d'))

# Create a folium map centered in the US
map_us = folium.Map(location=[39.8283, -98.5795], zoom_start=4)

# Add a line connecting the points in order of date
coordinates = [(entry['lat'], entry['lon']) for entry in data]
folium.PolyLine(coordinates, color='blue', weight=1.5, opacity=1).add_to(map_us)

# Add markers for each point
for entry in data:
    popup_text = f"Date: {entry['date']}<br>Description: {entry['description']}"
    # Make all national park vistits a special color and symbol
    if 'national park' in entry['description'].lower():
        # Add green markers for national parks
        folium.Marker(
            location=[entry['lat'], entry['lon']],
            popup=folium.Popup(popup_text, max_width=200),
            icon=folium.Icon(color='green', icon='leaf')
        ).add_to(map_us)
    else:
        # Add red markers with road icon for other locations
        folium.Marker(
            location=[entry['lat'], entry['lon']],
            popup=folium.Popup(popup_text, max_width=200),
            icon=folium.Icon(color='red', icon='road')
        ).add_to(map_us)

Future Use

The code can be modified slightly to work for any XML file to create a similar map. By modifying the way coordinates, names, and descriptions are extracted, the script can be used to create interactive maps for a variety of use cases, such as visualizing travel routes, locations of interest, or tracking events. Additionally, users can customize the markers and lines to represent different types of data, making the tool versatile for different applications.

Written by Adam Surette

← Back to all projects