Created a script to pull sighting data from
INatraulist in just the US based on species list
This commit is contained in:
1 parent
afa683b7e3
commit
b6873c829c
3 files changed
+659
No files matched your search
@@ -0,0 +1,88 @@
|
||||
"""
|
||||
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()
|
||||
Reference in new issue
Block a user