Context
Follow-up from PR #4215 (viz smart panel-heights + demo-dataset polish).
viz smart's time bucketing (src/cmd/viz.rs, enum TsBucket { Day, Week, Month } ~L13132) has three granularities and picks between them purely by the date column's observed span (ts_bucket_for_span, from the stats-cache min/max). There is no Quarter (or Year) bucket, and the selection ignores the data's native cadence.
This surfaced with the quarterly regions_growth.csv demo: a quarterly date column spanning ~15 months bucketed to weekly/monthly, so the "Records by <period>" time-series showed data every 3 months with empty periods between — it read as sparse/"weird". In PR #4215 the pragmatic fix was to make that demo monthly and dense instead, which sidestepped (but didn't solve) the underlying gap.
Important nuance discovered in #4215
The TimeSeries panel renders on a date x-axis (is_date → AxisType::Date, viz.rs:styled_x_axis). So a Quarter bucket by itself would not change the visual — quarterly points would still sit 3 months apart on a continuous date axis. To actually help, a Quarter bucket must be paired with either:
- quarter-aware tick labels (
YYYY-Qn) and/or a categorical x-axis (one evenly-spaced slot per bucket), and
- cadence-aware bucket selection so quarterly data is bucketed by quarter in the first place (span-based selection alone picks Week/Month for a ~1–2 year span).
Proposal
-
Add TsBucket::Quarter (and consider Year) with matching arms in:
ts_bucket_key (truncate to quarter-start month: 1/4/7/10, day 1)
ts_bucket_label (YYYY-Qn)
ts_bucket_word ("quarter")
choose_anim_bucket (~L13535) so the T3 Gapminder animation can use quarter frames
ts_bucket_for_span thresholds (Quarter/Year for multi-year spans)
-
Cadence-aware selection. Rather than span alone, pick the finest bucket that doesn't leave most periods empty — e.g. cap fineness by the date column's distinct-value count / typical spacing (the stats cache already has cardinality; choose_anim_bucket already does a distinct-count-based pick for the animation). Quarter-aligned dates → quarter buckets.
-
Rendering. Give bucketed TimeSeries/count panels quarter-appropriate ticks (or a categorical axis) so evenly-spaced quarters replace the gappy date-axis look.
The describegpt angle ("an additional temporal concept")
The concept vocabulary (src/cmd/describegpt/dictionary.rs, CONCEPT_VOCAB) already has time.* role concepts (time.date, time.event_timestamp, time.created_at, …) but nothing describing a date column's cadence/granularity (daily / weekly / monthly / quarterly / yearly). describegpt already infers dataset-level grain and temporal_coverage — inferring a date column's native cadence fits the same machinery.
Idea: describegpt infers a temporal-cadence attribute for date columns (either a new column attribute alongside concept/role, or a time.* cadence hint), and viz smart consumes it via the dictionary (like it already consumes measure.*/geo.* concepts) to drive bucket selection deterministically — instead of re-deriving cadence from the raw data each run. This would also let --dictionary/--smarter runs bucket correctly even when the span heuristic would guess wrong.
Open question: model cadence as a column attribute (cleaner — cadence is orthogonal to the timestamp's role) vs. a time.* concept token. Leaning attribute, but worth deciding during design.
Acceptance criteria
- A quarterly dataset (e.g. a quarterly
regions_growth-style CSV) produces a viz smart time-series bucketed and labeled by quarter, with no empty inter-quarter gaps.
choose_anim_bucket can select quarter frames for the T3 animated bubble.
- (Stretch) describegpt infers a date column's native cadence;
viz smart honors it from the dictionary.
- Tests:
ts_bucket_key/label/word for Quarter; cadence-aware selection on quarterly vs daily data; a gallery demo (restore a quarterly regions_growth variant) verifying the gap-free quarter axis.
Critical files
src/cmd/viz.rs — TsBucket, ts_bucket_for_span/_key/_label/_word (~L13132–13176), choose_anim_bucket (~L13535), TimeSeries bucket selection (~L13373), styled_x_axis date-axis handling.
src/cmd/describegpt/dictionary.rs — CONCEPT_VOCAB / temporal concepts; src/cmd/describegpt.rs — grain/temporal_coverage inference.
Context
Follow-up from PR #4215 (
viz smartpanel-heights + demo-dataset polish).viz smart's time bucketing (src/cmd/viz.rs,enum TsBucket { Day, Week, Month }~L13132) has three granularities and picks between them purely by the date column's observed span (ts_bucket_for_span, from the stats-cache min/max). There is no Quarter (or Year) bucket, and the selection ignores the data's native cadence.This surfaced with the quarterly
regions_growth.csvdemo: a quarterly date column spanning ~15 months bucketed to weekly/monthly, so the "Records by <period>" time-series showed data every 3 months with empty periods between — it read as sparse/"weird". In PR #4215 the pragmatic fix was to make that demo monthly and dense instead, which sidestepped (but didn't solve) the underlying gap.Important nuance discovered in #4215
The
TimeSeriespanel renders on a date x-axis (is_date→AxisType::Date,viz.rs:styled_x_axis). So a Quarter bucket by itself would not change the visual — quarterly points would still sit 3 months apart on a continuous date axis. To actually help, a Quarter bucket must be paired with either:YYYY-Qn) and/or a categorical x-axis (one evenly-spaced slot per bucket), andProposal
Add
TsBucket::Quarter(and considerYear) with matching arms in:ts_bucket_key(truncate to quarter-start month: 1/4/7/10, day 1)ts_bucket_label(YYYY-Qn)ts_bucket_word("quarter")choose_anim_bucket(~L13535) so the T3 Gapminder animation can use quarter framests_bucket_for_spanthresholds (Quarter/Year for multi-year spans)Cadence-aware selection. Rather than span alone, pick the finest bucket that doesn't leave most periods empty — e.g. cap fineness by the date column's distinct-value count / typical spacing (the stats cache already has cardinality;
choose_anim_bucketalready does a distinct-count-based pick for the animation). Quarter-aligned dates → quarter buckets.Rendering. Give bucketed
TimeSeries/count panels quarter-appropriate ticks (or a categorical axis) so evenly-spaced quarters replace the gappy date-axis look.The describegpt angle ("an additional temporal concept")
The concept vocabulary (
src/cmd/describegpt/dictionary.rs,CONCEPT_VOCAB) already hastime.*role concepts (time.date,time.event_timestamp,time.created_at, …) but nothing describing a date column's cadence/granularity (daily / weekly / monthly / quarterly / yearly). describegpt already infers dataset-levelgrainandtemporal_coverage— inferring a date column's native cadence fits the same machinery.Idea: describegpt infers a temporal-cadence attribute for date columns (either a new column attribute alongside
concept/role, or atime.*cadence hint), andviz smartconsumes it via the dictionary (like it already consumesmeasure.*/geo.*concepts) to drive bucket selection deterministically — instead of re-deriving cadence from the raw data each run. This would also let--dictionary/--smarterruns bucket correctly even when the span heuristic would guess wrong.Open question: model cadence as a column attribute (cleaner — cadence is orthogonal to the timestamp's role) vs. a
time.*concept token. Leaning attribute, but worth deciding during design.Acceptance criteria
regions_growth-style CSV) produces aviz smarttime-series bucketed and labeled by quarter, with no empty inter-quarter gaps.choose_anim_bucketcan select quarter frames for the T3 animated bubble.viz smarthonors it from the dictionary.ts_bucket_key/label/wordfor Quarter; cadence-aware selection on quarterly vs daily data; a gallery demo (restore a quarterlyregions_growthvariant) verifying the gap-free quarter axis.Critical files
src/cmd/viz.rs—TsBucket,ts_bucket_for_span/_key/_label/_word(~L13132–13176),choose_anim_bucket(~L13535), TimeSeries bucket selection (~L13373),styled_x_axisdate-axis handling.src/cmd/describegpt/dictionary.rs—CONCEPT_VOCAB/ temporal concepts;src/cmd/describegpt.rs—grain/temporal_coverageinference.