Project 1: Real-Time Earthquake Monitor
Build an interactive map that fetches live earthquake events, filters them, and renders a shareable HTML dashboard.
Quick Reference
| Attribute | Value |
|---|---|
| Difficulty | Beginner |
| Time Estimate | Weekend |
| Language | Python (Alternatives: R, Julia) |
| Prerequisites | Basic Python, JSON familiarity |
| Key Topics | GeoJSON, spatial filters, time windows, web maps |
| Output | HTML map + CLI summary |
Learning Objectives
By completing this project, you will:
- Parse GeoJSON FeatureCollections and extract geometry and properties.
- Convert timestamps from epoch milliseconds to readable time.
- Filter events by magnitude, time range, and bounding box.
- Render an interactive map with styled markers and popups.
- Explain how coordinate order and projections affect map output.
- Package results as a static HTML artifact you can share.
The Core Question You’re Answering
“How do I turn a live GeoJSON feed into a map that people can explore and trust?”
This is the same question behind real disaster dashboards: the data is noisy, the format is strict, and the visualization must be precise enough that users can make decisions from it.
Concepts You Must Understand First
| Concept | Why It Matters | Where to Learn |
|---|---|---|
| GeoJSON structure | You must extract coordinates and properties correctly | Python GIS intro (vector formats) |
| Coordinate order (lon, lat) | Incorrect order puts markers in the wrong hemisphere | GeoJSON spec + folium examples |
| Epoch timestamps | USGS feeds use epoch ms, not human time | Python datetime docs |
| Bounding boxes | Fast spatial filtering without heavy geometry | Any GIS basics guide |
| Web Mercator tiles | Your map uses a projection even if you do not notice | Map tiling docs |
Key Concepts Deep Dive
- GeoJSON FeatureCollections
- A FeatureCollection is a list of Features. Each Feature has
geometryandproperties. - For earthquakes, geometry is a Point and properties include magnitude, place, and time.
- A FeatureCollection is a list of Features. Each Feature has
- Time Windows
- The feed is a rolling window (past hour, day, week).
- Your filters must convert epoch milliseconds to UTC and compare consistently.
- Bounding Box Filters
- A bbox is
[min_lon, min_lat, max_lon, max_lat]. - Use bbox to reduce the dataset before rendering.
- A bbox is
- Marker Styling
- Magnitude is best shown with size and color.
- Depth can be shown with color or tooltip text.
Theoretical Foundation
The Live Data Pipeline
┌────────────┐ ┌──────────────┐ ┌───────────────┐ ┌──────────────┐
│ USGS Feed │ → │ GeoJSON Parse│ → │ Filter Events │ → │ Render Map │
└────────────┘ └──────────────┘ └───────────────┘ └──────────────┘
│ │ │ │
▼ ▼ ▼ ▼
HTTP GET Feature list Reduced list HTML output
GeoJSON Event Anatomy
A single earthquake feature looks like:
{
"type": "Feature",
"geometry": {"type": "Point", "coordinates": [-122.75, 38.78, 3.2]},
"properties": {"mag": 2.5, "place": "5km NE of City", "time": 1704067200000}
}
coordinates: lon, lat, depthproperties.mag: magnitude for size/colorproperties.time: epoch milliseconds
Why Projections Matter
Your markers are plotted on Web Mercator tiles. This is not a true-area projection, which means distances and areas are distorted at high latitudes. For a simple dashboard this is fine, but you must still respect coordinate order and scale carefully.
Project Specification
What You Will Build
A Python script that downloads the USGS GeoJSON feed, filters events, and writes a static HTML map with styled markers and popups.
Functional Requirements
- Fetch GeoJSON from a USGS endpoint.
- Filter by time window (hours back) and minimum magnitude.
- Optional bbox filter for region of interest.
- Render markers with size by magnitude and color by depth or magnitude.
- Save a standalone HTML file that opens in a browser.
Non-Functional Requirements
- Resilience: Handle empty feeds or API errors.
- Clarity: Popups show place, magnitude, time, and depth.
- Configurability: CLI args or config for filters.
Example Usage / Output
$ python earthquake_map.py --min-mag 3.0 --hours 24 --bbox "-125,32,-114,42"
Fetched 812 events
Filtered to 23 events
Saved map to output/earthquakes.html
Real World Outcome
You open output/earthquakes.html and see:
- A map centered on your region.
- Circles sized by magnitude and colored by depth.
- Clicking a marker shows a popup with place, magnitude, and UTC time.
- A short legend or note indicating filter settings.
Solution Architecture
High-Level Design
USGS Feed
|
v
requests.get -> response.json
|
v
filter_events(events, min_mag, hours, bbox)
|
v
render_map(filtered_events) -> HTML
Key Components
| Component | Responsibility | Key Decisions |
|---|---|---|
| Fetcher | Download GeoJSON | Endpoint selection and retries |
| Parser | Extract fields | Validate coordinate order |
| Filter | Apply time and bbox | Inclusive thresholds |
| Renderer | Create map | Folium marker style |
| Exporter | Save output | Output path naming |
Data Structures
class Event:
# lat, lon, depth, magnitude, time, place
Algorithm Overview
Event Filtering
- Convert event time from epoch ms to datetime.
- Skip events older than the time window.
- Skip events below minimum magnitude.
- If bbox is present, keep only points in bounds.
Complexity
- Time: O(n) for n events.
- Space: O(n) for filtered list.
Implementation Guide
Development Environment Setup
python -m venv geo-env
source geo-env/bin/activate
pip install requests folium
Project Structure
project-root/
├── src/
│ ├── earthquake_map.py
│ └── filters.py
├── output/
│ └── earthquakes.html
└── README.md
The Core Question You’re Answering
“How do I turn a raw GeoJSON feed into a trustworthy, usable map?”
Concepts You Must Understand First
- GeoJSON Fields
- Know where magnitude, time, and coordinates live.
- Datetime Conversion
- Epoch ms to UTC datetime.
- Spatial Filtering
- Bbox filter logic and edge cases.
Questions to Guide Your Design
- What filters are most useful for users?
- How will you prevent marker clutter?
- What fields belong in popups vs tooltips?
- Should you log the filter counts for transparency?
Thinking Exercise
Take one feature from the feed and manually compute:
- The latitude and longitude.
- The human readable timestamp.
- Whether it passes your filters.
Interview Questions
- What is GeoJSON and how is it structured?
- Why is coordinate order important?
- How do you filter points inside a bounding box?
- What projection do web maps use and why?
- How do you handle missing properties in live data?
- How would you cluster markers for dense regions?
- How do you make this usable offline?
Hints in Layers
- Hint 1: Print one feature and map its fields.
- Hint 2: Build a map with a single hard-coded marker.
- Hint 3: Add filtering and track counts after each step.
- Hint 4: Add marker clustering if the map slows down.
Books That Will Help
| Topic | Book | Chapter |
|---|---|---|
| GeoJSON | “Introduction to Python for Geographic Data Analysis” | Vector data |
| Web maps | Folium docs | Quickstart |
| Time handling | Python docs | datetime |
Implementation Phases
Phase 1: Fetch and Parse (2-3 hours)
- Download GeoJSON
- Inspect a sample feature
- Extract event fields
Checkpoint: You can print a clean list of events.
Phase 2: Filtering and CLI (3-5 hours)
- Add time and magnitude filters
- Add bbox filters
- Log filter counts
Checkpoint: You can reduce events to a region reliably.
Phase 3: Visualization (3-5 hours)
- Render markers and popups
- Add legend or note
- Save HTML output
Checkpoint: Map is shareable and informative.
Key Implementation Decisions
| Decision | Options | Recommendation | Rationale |
|---|---|---|---|
| Map library | Folium, Plotly, Leafmap | Folium | Simple HTML output |
| Filter interface | CLI args, config | CLI args | Fast iteration |
| Marker style | circle, icon | circle | Encodes magnitude easily |
Testing Strategy
Test Categories
| Category | Purpose | Examples |
|---|---|---|
| API fetch | Data returned | Non-empty feature list |
| Filter logic | Correct counts | Known small dataset |
| Output | HTML saved | File exists and opens |
Critical Test Cases
- Empty feed or API error.
- Bbox that excludes all events.
- Events with missing properties.
Common Pitfalls and Debugging
| Pitfall | Symptom | Solution |
|---|---|---|
| Lat/lon swapped | Markers appear far away | Always use lon, lat from GeoJSON |
| Wrong time unit | No events | Convert ms to seconds correctly |
| Too many markers | Slow map | Use clustering or filters |
Extensions and Challenges
- Add clustering and heatmap layers.
- Add alerts for events within a radius of a point.
- Add auto-refresh with a timestamp overlay.
Real-World Connections
- Disaster dashboards and public alert systems.
- News organizations mapping global earthquakes.
- Emergency management spatial awareness tools.
Resources
- USGS Earthquake API: https://earthquake.usgs.gov/fdsnws/event/1/
- Folium docs: https://python-visualization.github.io/folium/
- GeoJSON spec: https://geojson.org/
Self-Assessment Checklist
- I can parse GeoJSON and explain its structure.
- I can filter events by time and space.
- I can render a map with meaningful styling.
- I can explain how projections affect web maps.
Submission / Completion Criteria
Minimum Viable Completion
- Fetch and render events on a map with at least one filter.
Full Completion
- Time and magnitude filters, plus popups with details.
Excellence
- Clustering, heatmaps, and alerting features.
This guide was generated from GEOSPATIAL_PYTHON_LEARNING_PROJECTS.md. For the complete learning path, see the parent directory GEOSPATIAL_PYTHON_LEARNING_PROJECTS/README.md.