Skip to content

feat(viz): barpolar wind rose; clock-face polar bars for the smart seasonality panel - #4840

Merged
jqnatividad merged 6 commits into
masterfrom
feat/viz-barpolar
Oct 18, 2026
Merged

jqnatividad merged 6 commits into
masterfrom
feat/viz-barpolar

Conversation

@jqnatividad

Copy link
Copy Markdown
Collaborator

Stacked on #4839 (parcoords), which is stacked on #4838 (the plotly.rs pin bump). Retarget to master once both merge.

What's new

  • viz barpolar: a polar bar chart (wind rose). One bar per --x category, clockwise from north.
    • Bar length is the --agg of --y (sum by default), or the row count when --y is omitted. --agg sum/mean/min/max without --y is a usage error.
    • --series stacks colored segments. When every series label starts with a number (0-10, 10-20, 30+), they stack low to high; otherwise first-appearance order.
    • Angular placement:
      • Compass labels (N, NE, NNE…, case-insensitive) sit at their true bearings on a full 8- or 16-point rose, so a direction with no data stays an empty slot instead of shifting the others.
      • Other categories get evenly spaced slots in first-appearance order (numeric labels sort ascending). The axis is forced to category, because plotly would otherwise read hour or month numbers as degrees and bunch them into a narrow wedge.
      • --degrees (new option, barpolar only) reads a numeric --x as a true bearing on a linear angular axis, folding 360 onto 0. A non-numeric value is an error, and --degrees on any other chart is a usage error.
    • Negative totals are rejected, as in viz funnel.
  • viz smart seasonality panel:
    • Draws one BarPolar bar per hour, day or month instead of a filled ScatterPolar ring, so each phase is its own hover target ("Thu, 1.44× average").
    • Now reads like a 24-hour dial: the first phase (00h, Mon, Jan) at the top, running clockwise. It previously started at 3 o'clock and ran counterclockwise (plotly's default), which an hour ring invites misreading as a clock.
    • The panel is HTML-only, so there is no static-export twin to change.
  • plotly.rs pin moved to 3223bd7 (two commits added to Release 0.15.0: complete plotly.js 3.7 trace coverage, remove kaleido/EPS, dependency security bumps plotly/plotly.rs#442):
    • The polar layout structs no longer serialize unset fields as null.
    • The plotly_dark template now styles polar and ternary subplots, matching plotly.py. Before this, viz radar and viz barpolar with --theme plotly_dark drew a white polar disc on the dark page; viz radar already did this on master. Ternary is covered for the upcoming viz ternary. 3D-scene styling is still missing, because plotly.rs axes have no background attributes yet.
  • No new i18n keys: the count label reuses viz.chart.count, and the panel hover reuses viz.hover.polar_index.
  • Regenerated docs/help/viz.md and qsv-viz.json (new subcommand, --degrees, the --series/--agg descriptions, two examples).

Gallery

  • New wind rose figure from a synthetic wind_obs.csv (1,440 hourly observations, prevailing south-westerlies), listed in the README dataset table.
  • The four dashboards with a seasonality panel (smart_allegheny_dogs, smart_nyc311, smart_timeseries, smart_wpa_211_requests) are regenerated for the clock-face polar bars. Dashboards whose only regen diff was timestamps were not committed.

Not regenerated

The Pittsburgh, Boston and Brazil link-out dashboards (pitt311data.html, smart_boston_311_2025.html, smart-brazil-lpg-4-semanas.html) keep the old line rings: their source data isn't committed.

Verification

  • cargo t viz -F all_features: 485 unit and 654 integration tests pass. 7 new barpolar integration tests; the 8 seasonality tests now assert barpolar and the clock-face axis on every ring.
  • Mutation-checked: reverting the panel to ScatterPolar, disabling compass placement, the 16-point rose, --degrees normalization and its linear axis, the numeric slot sort, the sum default, the binned-series sort and the clockwise direction each fails a test.
  • scripts/double-run-check.py --check OK; cargo +nightly fmt; clippy reports no warnings on added lines; cargo build --locked (the lockfile change is only the three plotly entries); qsvlite builds.
  • In Chrome: wind rose by compass names (with gaps) and by --degrees, the gallery figure, three dashboards' seasonality panels (hover, clock layout, three side-by-side rings), and dark-theme barpolar/radar.

The wiki Visualization page update is staged locally and will be pushed after merge.

🤖 Generated with Claude Code

@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

Base automatically changed from feat/viz-parcoords to master October 18, 2026 18:29
jqnatividad and others added 6 commits October 18, 2026 14:29
…anel

`viz barpolar` draws one bar per --x category, clockwise from north,
sized by the --agg of --y (sum by default) or the row count when --y is
omitted; --series stacks segments, in numeric order for binned series.

Compass labels (N, NE, NNE...) are placed on a full 8- or 16-point rose
so a missing direction keeps its empty slot instead of shifting the
others. Other categories get evenly spaced slots (numeric ones sorted
ascending); --degrees reads a numeric --x as a true bearing on a linear
angular axis, folding 360 onto 0.

The smart cyclic panel now draws a BarPolar per ring instead of a
filled ScatterPolar, so each hour/day/month is its own bar and hover
target; rings are stored unclosed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… seasonality panels

Adds a synthetic wind_obs.csv (1,440 hourly observations) for the wind
rose figure. The four dashboards with a seasonality panel are
regenerated so it draws polar bars.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…l field

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fork's LayoutPolar and polar axes serialized every unset field as
null; 43a4ee4 omits them. viz barpolar's layout now carries only the
fields it sets, and a test asserts no null bgcolor/radialaxis.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rs pin

The seasonality rings now start at 12 o'clock and run clockwise, like
`viz barpolar` and a clock face; they started at 3 o'clock and ran
counterclockwise (plotly's default), so an hour ring could be misread
as a clock.

Moves the plotly.rs pin to 3223bd7, whose plotly_dark template styles
polar and ternary subplots, so `viz radar`/`viz barpolar` with
--theme plotly_dark no longer draw a white polar disc. Regenerates the
gallery and the four dashboards with a seasonality panel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jqnatividad
jqnatividad merged commit 9565651 into master Oct 18, 2026
31 checks passed
@jqnatividad
jqnatividad deleted the feat/viz-barpolar branch October 18, 2026 18:40
jqnatividad added a commit that referenced this pull request Oct 19, 2026
Full refresh via refresh_external_dashboards.sh (the five dashboards built
from external datasets) followed by gen_gallery.py (every other page and
gallery.html), so the whole gallery is on one binary. QSV_VIZ_REGEN_LLM=1:
the four --dictionary infer pages reused their committed .schema.json
sidecars; no LLM was contacted. gallery.html itself is byte-identical
(58 figures); 23 dashboard pages changed.

Beyond version/Compiled stamps:
- 3 pages with seasonality panels swap 6 scatterpolar rings for barpolar
  bars (#4840): pitt311data, brazil-lpg, boston_311_2025.
- 3 pages last built by 24.0.0 gain the parallel-coordinates panel (#4839)
  plus panels added in 25.0.0: colombia-calidad-aire, dict_sunburst,
  pa_crashes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant