[FEAT] frame: flag and generate the local birds the bundle is missing
This commit is contained in:
+57
-3
@@ -194,13 +194,67 @@ def species_for_zip(zip_code, country="us", target=10, days=7, radii=(15, 30, 50
|
||||
return found[:target]
|
||||
|
||||
|
||||
def coverage_for_zip(zip_code, country="us", sample=15, days=7, radii=(15, 30, 50),
|
||||
apt_js=APT_JS, timeout=20):
|
||||
"""Split the ZIP's most-detected birds by whether the repo can draw them.
|
||||
|
||||
Same gather as species_for_zip (grow the radius, then triangulate / eBird
|
||||
for sparse spots) but UNFILTERED, capped at the top `sample` by count, then
|
||||
partitioned. Returns (have, missing) as [{sci,com,n}] lists sorted by count:
|
||||
`have` are bundled today, `missing` are the local birds with no cutout yet -
|
||||
the set the installer offers to generate. `sample` sits a little above the
|
||||
render's `target` (10) so a few extra cover BirdWeather count drift without
|
||||
generating birds that never reach the collage. The split is always against
|
||||
the current bundle, so adding illustrations upstream shrinks `missing` free.
|
||||
"""
|
||||
lat, lon = geocode(zip_code, country, timeout)
|
||||
top = []
|
||||
for miles in radii:
|
||||
top = top_species(lat, lon, miles, days, 60, timeout)
|
||||
if len(top) >= sample:
|
||||
break
|
||||
if len(top) < sample:
|
||||
tri = triangulate(lat, lon, 3, days, timeout)
|
||||
if len(tri) > len(top):
|
||||
top = tri
|
||||
if len(top) < sample:
|
||||
eb = ebird_nearby(lat, lon, days * 2, timeout=timeout)
|
||||
if len(eb) > len(top):
|
||||
top = eb
|
||||
top.sort(key=lambda s: -(s["n"] or 0))
|
||||
top = top[:sample]
|
||||
drawable = drawable_slugs(apt_js)
|
||||
have = [s for s in top if slugify(s["sci"]) in drawable]
|
||||
missing = [s for s in top if slugify(s["sci"]) not in drawable]
|
||||
return have, missing
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
ap = argparse.ArgumentParser(description="Print BirdWeather top drawable species for a ZIP.")
|
||||
import sys
|
||||
ap = argparse.ArgumentParser(description="BirdWeather top species for a ZIP.")
|
||||
ap.add_argument("zip")
|
||||
ap.add_argument("--country", default="us")
|
||||
ap.add_argument("--target", type=int, default=10)
|
||||
ap.add_argument("--days", type=int, default=7)
|
||||
ap.add_argument("--missing", action="store_true",
|
||||
help="Print the ZIP's top LOCAL birds the repo can't draw yet "
|
||||
"as Sci|Com lines (feed to pregen.py --stdin); summary to stderr.")
|
||||
ap.add_argument("--sample", type=int, default=15,
|
||||
help="How many of the ZIP's top birds to weigh for --missing (default 15).")
|
||||
a = ap.parse_args()
|
||||
for s in species_for_zip(a.zip, a.country, a.target, a.days):
|
||||
print(f'{s["n"]:>8} {s["com"]} ({s["sci"]})')
|
||||
if a.missing:
|
||||
try:
|
||||
have, missing = coverage_for_zip(a.zip, a.country, a.sample, a.days)
|
||||
except Exception as e:
|
||||
# Never break the installer: no data just means no generation offer.
|
||||
print(f"coverage lookup failed: {e}", file=sys.stderr)
|
||||
sys.exit(0)
|
||||
for s in missing:
|
||||
print(f'{s["sci"]}|{s["com"]}')
|
||||
total = len(have) + len(missing)
|
||||
print(f"{len(have)} of the top {total} birds near {a.zip} are bundled; "
|
||||
f"{len(missing)} are not.", file=sys.stderr)
|
||||
else:
|
||||
for s in species_for_zip(a.zip, a.country, a.target, a.days):
|
||||
print(f'{s["n"]:>8} {s["com"]} ({s["sci"]})')
|
||||
|
||||
Reference in New Issue
Block a user