""" Visualize species sighting coordinates overlaid on a map. Usage: python dev_scripts/map_viewer.py # shows all species python dev_scripts/map_viewer.py "Mallard" # filter by common name (partial match) python dev_scripts/map_viewer.py --list # list all available species Requires: pip install folium """ import csv import json import sys import webbrowser from pathlib import Path SIGHTINGS_FILE = Path(__file__).parent.parent / "wildlife" / "portland_wildlife_sightings.csv" OUTPUT_HTML = Path(__file__).parent.parent / "wildlife" / "sightings_map.html" PORTLAND_CENTER = [45.5051, -122.6750] def load_sightings(filter_name: str | None = None) -> list[dict]: rows = [] with open(SIGHTINGS_FILE, newline="", encoding="utf-8") as f: for row in csv.DictReader(f): coords = json.loads(row["sighting_coordinates"]) if not coords: continue if filter_name and filter_name.lower() not in row["common_name"].lower(): continue rows.append({ "taxon_id": row["taxon_id"], "common_name": row["common_name"], "scientific_name": row["scientific_name"], "coords": coords, }) return rows def build_map(species_list: list[dict]) -> str: try: import folium except ImportError: print("folium is not installed. Run: pip install folium") sys.exit(1) m = folium.Map(location=PORTLAND_CENTER, zoom_start=11, tiles="OpenStreetMap") for sp in species_list: for lat, lng in sp["coords"]: folium.CircleMarker( location=[lat, lng], radius=5, color="red", fill=True, fill_color="red", fill_opacity=0.7, tooltip=f"{sp['common_name']}
{sp['scientific_name']}", ).add_to(m) return m._repr_html_() def main(): if "--list" in sys.argv: with open(SIGHTINGS_FILE, newline="", encoding="utf-8") as f: for row in csv.DictReader(f): coords = json.loads(row["sighting_coordinates"]) print(f" {row['common_name']:40s} {len(coords)} sightings") return filter_name = next((a for a in sys.argv[1:] if not a.startswith("--")), None) species_list = load_sightings(filter_name) if not species_list: print(f"No species found matching '{filter_name}'") return print(f"Plotting {len(species_list)} species...") html = build_map(species_list) OUTPUT_HTML.write_text(html, encoding="utf-8") print(f"Map saved to {OUTPUT_HTML}") webbrowser.open(OUTPUT_HTML.as_uri()) if __name__ == "__main__": main()