From 665518aa5615548cdafea9afc83f00697efad069 Mon Sep 17 00:00:00 2001 From: "mason@agscout.ai" Date: Wed, 21 Oct 2026 06:22:43 -0700 Subject: [PATCH] Homepage: drop the last-7-days charts, show crops covered instead of CV task types The two "Last 7 days" panels only ever showed a flat line between hand-run snapshots, so they are removed along with the forward-fill helper that fed them. The stats row's third figure is now the number of distinct crops named by top-level datasets (species rolled up from iNatAg's child datasets are excluded, since they are wild plants, not crops). Co-Authored-By: Claude Fable 5.1 --- src/lib/datasetHistory.ts | 29 --------- src/lib/datasets.ts | 11 ++++ src/pages/index.tsx | 121 +++++++++++++------------------------- 3 files changed, 53 insertions(+), 108 deletions(-) diff --git a/src/lib/datasetHistory.ts b/src/lib/datasetHistory.ts index 09ad138..f730253 100644 --- a/src/lib/datasetHistory.ts +++ b/src/lib/datasetHistory.ts @@ -11,11 +11,6 @@ export interface DatasetHistoryAnnotation extends GrowthAnnotation { metric: 'datasetCount' | 'imageCount'; } -function formatShortDate(iso: string): string { - const d = new Date(`${iso}T00:00:00Z`); - return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', timeZone: 'UTC' }); -} - // Buckets points into fixed-length windows (in days) counted from the earliest point's date, // keeping the most recent point in each window. Snapshots are appended by hand at whatever // cadence someone happens to run the script, so this is what turns that irregular series into an @@ -57,27 +52,3 @@ export function remapAnnotations( return { ...annotation, atPeriod: closest.period }; }); } - -// Builds one point per calendar day for the last `days` days (ending today), forward-filling -// each day with the most recent snapshot on or before it — snapshots aren't taken daily, so -// without this a daily chart would just be gaps. -export function lastNDaysForwardFilled(points: DatasetHistoryPoint[], days: number): DatasetHistoryPoint[] { - if (points.length === 0) return []; - const sorted = [...points].sort((a, b) => a.date.localeCompare(b.date)); - const today = new Date(); - today.setUTCHours(0, 0, 0, 0); - - const result: DatasetHistoryPoint[] = []; - let cursor = 0; - let carried = sorted[0]; - for (let i = days - 1; i >= 0; i--) { - const day = new Date(today.getTime() - i * 86_400_000); - const dayIso = day.toISOString().slice(0, 10); - while (cursor < sorted.length && sorted[cursor].date <= dayIso) { - carried = sorted[cursor]; - cursor += 1; - } - result.push({ ...carried, period: formatShortDate(dayIso), date: dayIso }); - } - return result; -} diff --git a/src/lib/datasets.ts b/src/lib/datasets.ts index 46e3d74..0748a7a 100644 --- a/src/lib/datasets.ts +++ b/src/lib/datasets.ts @@ -730,6 +730,7 @@ export interface DatasetStats { datasetCount: number; imageCount: number; taskTypeCount: number; + cropCount: number; } // `parent_dataset` means two different things depending on the record. On vision datasets it @@ -793,11 +794,21 @@ export function computeDatasetStats(datasets: Dataset[]): DatasetStats { .map((dataset) => dataset.machine_learning_task) .filter((task): task is string => Boolean(task)), ).size; + // Distinct crops named by top-level datasets. Species rolled up from child datasets + // (`child_crop_types`) are left out: iNatAg alone contributes ~2,900 wild plant species, + // which would swamp the count and aren't crops. + const cropCount = new Set( + topLevel + .flatMap((dataset) => dataset.crop_types ?? []) + .map((crop) => crop.trim().toLowerCase()) + .filter(Boolean), + ).size; return { datasetCount: topLevel.length, imageCount, taskTypeCount, + cropCount, }; } diff --git a/src/pages/index.tsx b/src/pages/index.tsx index a22e71d..02c3bf3 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -17,7 +17,6 @@ import GrowthLineChart from '../components/GrowthLineChart'; import DistributionBarChart from '../components/DistributionBarChart'; import { bucketByInterval, - lastNDaysForwardFilled, remapAnnotations, type DatasetHistoryAnnotation, type DatasetHistoryPoint, @@ -174,19 +173,18 @@ function StatsRow() { Labeled images
- {stats.taskTypeCount.toLocaleString()} - CV task types + {stats.cropCount.toLocaleString()} + Crops covered
); } // Every point in dataset_history.json is a hand-run snapshot at whatever cadence someone -// happened to run the script, so the long-range charts are bucketed down to one point every two -// weeks for an even x-axis, and annotations are re-anchored to whichever bucketed point survives -// closest to their original snapshot. +// happened to run the script, so the charts are bucketed down to one point every two weeks for +// an even x-axis, and annotations are re-anchored to whichever bucketed point survives closest +// to their original snapshot. const BIWEEKLY_DAYS = 14; -const RECENT_DAYS = 7; function GrowthCharts() { const history = useDatasetHistory(); @@ -195,82 +193,47 @@ function GrowthCharts() { () => (history ? bucketByInterval(history.points, BIWEEKLY_DAYS) : []), [history], ); - const recent = useMemo( - () => (history ? lastNDaysForwardFilled(history.points, RECENT_DAYS) : []), - [history], - ); return ( - <> -
-

Growth over time

-
-
-

Top-level datasets over time

- {history ? ( - ({ period: p.period, date: p.date, value: p.datasetCount }))} - annotations={remapAnnotations( - history.annotations.filter((a) => a.metric === 'datasetCount'), - history.points, - biweekly, - )} - color="primary" - yaxisTitle="Top-level datasets" - /> - ) : ( -
Loading…
- )} -
-
-

Images over time

- {history ? ( - ({ period: p.period, date: p.date, value: p.imageCount }))} - annotations={remapAnnotations( - history.annotations.filter((a) => a.metric === 'imageCount'), - history.points, - biweekly, - )} - color="teal" - yaxisTitle="Images" - /> - ) : ( -
Loading…
- )} -
+
+

Growth over time

+
+
+

Top-level datasets over time

+ {history ? ( + ({ period: p.period, date: p.date, value: p.datasetCount }))} + annotations={remapAnnotations( + history.annotations.filter((a) => a.metric === 'datasetCount'), + history.points, + biweekly, + )} + color="primary" + yaxisTitle="Top-level datasets" + /> + ) : ( +
Loading…
+ )}
-
-
-

Last 7 days

-
-
-

Top-level datasets

- {history ? ( - ({ period: p.period, date: p.date, value: p.datasetCount }))} - color="primary" - yaxisTitle="Top-level datasets" - /> - ) : ( -
Loading…
- )} -
-
-

Images

- {history ? ( - ({ period: p.period, date: p.date, value: p.imageCount }))} - color="teal" - yaxisTitle="Images" - /> - ) : ( -
Loading…
- )} -
+
+

Images over time

+ {history ? ( + ({ period: p.period, date: p.date, value: p.imageCount }))} + annotations={remapAnnotations( + history.annotations.filter((a) => a.metric === 'imageCount'), + history.points, + biweekly, + )} + color="teal" + yaxisTitle="Images" + /> + ) : ( +
Loading…
+ )}
-
- +
+
); }