Files
WildDex/dev_scripts/map_viewer.py
T
Suppai_Neko b6873c829c Created a script to pull sighting data from
INatraulist in just the US based on species list
2026-03-27 13:51:36 -07:00

89 lines
2.8 KiB
Python

"""
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']}<br><i>{sp['scientific_name']}</i>",
).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()