Visitar URL original
feat(pivot-table): reintroduce show-values-as-fraction display option by rusackas · Pull Request #42761 · apache/superset · GitHub
Skip to content

feat(pivot-table): reintroduce show-values-as-fraction display option - #42761

Merged
sadpandajoe merged 10 commits into
masterfrom
feat/pivot-table-fraction-of
Aug 5, 2026
Merged

sadpandajoe merged 10 commits into
masterfrom
feat/pivot-table-fraction-of

Conversation

@rusackas

@rusackas rusackas commented Aug 4, 2026

Copy link
Copy Markdown
Member

SUMMARY

#41463 (SIP-216, merged via #41184) correctly moved Pivot Table totals/subtotals to DB-computed rollup queries, fixing non-additive metrics (ratios, COUNT_DISTINCT, AVG, etc.) that were previously wrong when re-aggregated client-side. As part of that change, the Pivot Table's old "Aggregation function" control was removed entirely, and its "Sum as Fraction of Total/Rows/Columns" options went with it.

That was collateral damage, not something the SIP identified as broken: those fraction variants only ever wrapped Sum/Count (both additive), so they were mathematically correct even before #41184, and users are now asking for the display mode back (originally raised against #41463).

This reintroduces it as a standalone "Show values as" control, rather than resurrecting the removed per-metric "Aggregation function" selector. The new architecture actually makes this cleaner than before: every cell already holds a DB-correct rollup value at every scope (its own cell, row total, column total, grand total), so showing a value as a fraction of one of those scopes is now a pure presentational transform at render time. It reuses react-pivottable's existing fractionOf template — the same one the old "Sum as Fraction of ..." options used — wrapping the current passthrough cellValue aggregator instead of sum()/count(), and reusing the same row/column/grand-total lookup (getAggregator) the removed feature relied on. No new query, no touching grouping_sets, no per-metric control to reintroduce.

Percentage display always uses a fixed percent format; a per-metric custom formatter (currency, decimals, etc.) doesn't apply to a ratio, so custom column formatters are skipped while a fraction mode is active (matching the old behavior, which also always used a fixed percent formatter regardless of the metric's own format).

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

Pivot table of birth_names (rows = state, columns = gender, metric = sum__num, row/column totals on), cycling through the new control:

Actual values (default, unchanged behavior):

Actual values, with row and column totals

% of row total — every row (and the row-total column) sums to 100.0%:

Percent of row total

% of column total — every column (and the column-total row) sums to 100.0%:

Percent of column total

% of grand total — the grand-total corner reads 100.0%, every other cell is its share of it:

Percent of grand total

The control itself, alongside the rest of the Options panel:

Show values as control, dropdown open showing all four options

TESTING INSTRUCTIONS

  1. Create or open a Pivot Table chart with at least one row grouping, one column grouping, and one metric.
  2. In the Options panel, find the new Show values as control (below "Combine metrics") and select "% of row total", "% of column total", or "% of grand total".
  3. Confirm cell values re-render as percentages without a new query being issued (it's a renderTrigger control).
  4. Confirm each row's percentages sum to 100% in "% of row total" mode, each column's percentages sum to 100% in "% of column total" mode, and the grand total cell always reads 100%.
  5. Switch back to "Actual values" (the default) and confirm the original numeric display returns.
  6. npx jest --runInBand plugins/plugin-chart-pivot-table — all 96 tests pass, including 5 new tests covering all three fraction modes plus the default/unset case.
  7. npx tsc --noEmit -p plugins/plugin-chart-pivot-table/tsconfig.json and pre-commit run on the changed files both pass clean.

ADDITIONAL INFORMATION

Issue #41463 (SIP-216, merged via #41184) correctly moved pivot table
totals/subtotals to DB-computed rollup queries, fixing non-additive
metrics (ratios, COUNT_DISTINCT, AVG, etc.). As part of that, the
Pivot Table's old "Aggregation function" control was removed
entirely, taking its "Sum as Fraction of Total/Rows/Columns" options
down with it -- collateral damage, not something the SIP identified
as broken. Those variants only ever wrapped Sum/Count (both
additive), so they were already correct before #41184 and remain a
distinct, wanted feature independent of the non-additive-totals fix.

This reintroduces it as a standalone "Show values as" control rather
than resurrecting the old per-metric aggregator-override mechanism.
Now that every cell already holds a DB-correct rollup value at every
scope (row total, column total, grand total), showing a cell as a
fraction of one of those scopes is a pure presentational transform at
render time: reuse react-pivottable's existing fractionOf template,
wrapping the passthrough `cellValue` aggregator instead of `sum()`/
`count()`, and reuse the same row/column/grand-total lookup
(`getAggregator`) the removed feature relied on. No new query, no
touching grouping_sets, no per-metric control.

Percentage display always uses a fixed percent format; per-metric
custom formatters (currency, decimals, etc.) don't apply to a ratio,
so formattedAggregators is skipped while a fraction mode is active.
@bito-code-review

bito-code-review Bot commented Aug 4, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #f318ab

Actionable Suggestions - 0
Review Details
  • Files reviewed - 7 · Commit Range: cdb52e5..cdb52e5
    • superset-frontend/plugins/plugin-chart-pivot-table/src/PivotTableChart.tsx
    • superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx
    • superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/transformProps.ts
    • superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/utilities.ts
    • superset-frontend/plugins/plugin-chart-pivot-table/src/types.ts
    • superset-frontend/plugins/plugin-chart-pivot-table/test/plugin/transformProps.test.ts
    • superset-frontend/plugins/plugin-chart-pivot-table/test/react-pivottable/tableRenders.test.tsx
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • Eslint (Linter) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@dosubot dosubot Bot added change:frontend Requires changing the frontend viz:charts:pivot Related to the Pivot Table charts labels Aug 4, 2026
@bito-code-review

Copy link
Copy Markdown
Contributor

The flagged issue is correct. The showValuesAs control exposes percentage options that require specific rollup levels (row, column, or grand totals) to calculate correctly. If these rollups are disabled in the pivot table configuration, the calculation logic will fail to find the required denominator, resulting in NaN% or Infinity% values.

To resolve this, you can update the controlPanel.tsx to conditionally disable these choices based on the state of the rollup toggles. You can use the visibility property in the control configuration to hide or disable the percentage options when the corresponding totals are not enabled.

Example implementation for controlPanel.tsx:

// Inside controlPanel.tsx, update the showValuesAs control configuration:
visibility: ({ controls }) => {
  const rowTotals = controls?.rowTotals?.value;
  const colTotals = controls?.colTotals?.value;
  // Logic to filter choices based on rowTotals/colTotals
  return { ... };
},

I have checked the available comments on this PR, and there are no other review comments to address. Would you like me to proceed with implementing this fix in the controlPanel.tsx file?

superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx

visibility: ({ controls }) => {
                const rowTotals = controls?.rowTotals?.value;
                const colTotals = controls?.colTotals?.value;
                // Logic to filter choices based on rowTotals/colTotals
                return { ... };
              },

@codecov

codecov Bot commented Aug 4, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.47170% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.76%. Comparing base (0e4e368) to head (1681dad).

Files with missing lines Patch % Lines
...hart-pivot-table/src/react-pivottable/utilities.ts 66.66% 13 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #42761      +/-   ##
==========================================
+ Coverage   65.75%   65.76%   +0.01%     
==========================================
  Files        2842     2842              
  Lines      162277   162314      +37     
  Branches    37173    37197      +24     
==========================================
+ Hits       106711   106752      +41     
+ Misses      53498    53494       -4     
  Partials     2068     2068              
Flag Coverage Δ
hive 38.03% <ø> (ø)
javascript 72.09% <75.47%> (+0.01%) ⬆️
mysql 57.82% <ø> (ø)
postgres 57.87% <ø> (ø)
presto 39.95% <ø> (ø)
python 59.25% <ø> (ø)
sqlite 57.50% <ø> (ø)
unit 100.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

… totals toggle

`showValuesAs` percent modes (% of row/column/grand total) divide by a
rollup level that `buildGroupbyCombinations` only queried when the
matching Total/subtotal display toggle was on, so picking a percent
mode without enabling that toggle could crash on a missing denominator
aggregator. Force the required level(s) in and fall back to a blank
cell instead of throwing if one is ever still missing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@rusackas
rusackas requested a review from Vitor-Avila August 4, 2026 23:00
@rusackas rusackas added the 🎪 ⚡ showtime-trigger-start Create new ephemeral environment for this PR label Aug 4, 2026
@github-actions github-actions Bot added 🎪 490356d 🚦 building 🎪 ⌛ 48h Environment expires after 48 hours (default) and removed 🎪 ⚡ showtime-trigger-start Create new ephemeral environment for this PR labels Aug 4, 2026
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

🎪 Showtime is building environment on GHA for 490356d

@rusackas rusackas removed the 🎪 ⌛ 48h Environment expires after 48 hours (default) label Aug 4, 2026
… pruning test

buildGroupbyCombinations iterates rows as the outer loop and columns as
the inner loop, so when both the rows-collapsed and columns-collapsed
levels are pruned in (the percent_total case), the rows-collapsed
level pairs with every column prefix before the leaf row prefix does
-- matching the row/col-only pruning tests directly above it. The new
percent_total test had those two entries swapped; order carries no
functional meaning downstream (transformProps/PivotData key off each
row's own tags, not array position), so this fixes the expectation
rather than the (correct) production code.
@github-actions github-actions Bot added 🎪 f4a5010 🚦 building 🎪 ⌛ 48h Environment expires after 48 hours (default) labels Aug 4, 2026
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

🎪 Showtime is building environment on GHA for 9492b26

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

🎪 Showtime deployed environment on GHA for 9492b26

• Environment: http://34.215.90.107:8080 (admin/admin)
• Lifetime: 48h auto-cleanup
• Updates: New commits create fresh environments automatically

@eschutho eschutho left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Posting on Elizabeth's behalf — this is her PR reviewer agent. Forward any pushback to her and she'll loop me back in.

Left a few notes below — one functional item worth a look before merge, plus two related test-coverage gaps. All line numbers verified against HEAD f4a5010a84ab387a09858ac7372ab340cdb7f880.

superset-frontend/plugins/plugin-chart-pivot-table/src/plugin/controlPanel.tsx#L246-L268

showValuesAs is registered as renderTrigger: true, but buildGroupbyCombinations uses formData.showValuesAs to decide which grouping_sets levels to request for non-additive metrics (AVG, COUNT_DISTINCT, ratios), and that only runs when the query itself is rebuilt. Since rowTotals/colTotals/rowSubTotals/colSubTotals all default to false, a fresh Pivot Table with a non-additive metric that's switched straight to "% of grand total" wouldn't trigger a requery — every cell would fall through the new denominatorAggregator.inner guard below to blank, with no error or obvious reason why. Additive metrics (SUM/COUNT) aren't affected since their totals are synthesized client-side from the always-fetched leaf rows.

WDYT — should showValuesAs drop renderTrigger so it forces a requery, or would it make more sense for buildQuery to always request the totals/grand-total levels regardless of the display toggles?


superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/utilities.ts#L756-L767

This null-guard on denominatorAggregator.inner is only reachable when the requested denominator level is missing from the data — which is exactly the staleness scenario above — but nothing in the test suite constructs PivotData with a level missing to exercise it.

Could we add a test that omits e.g. the grand-total record from the input and asserts the affected cells render blank rather than throwing? Useful either way the item above gets resolved, and it'd pin down the current fallback behavior.


superset-frontend/plugins/plugin-chart-pivot-table/test/react-pivottable/tableRenders.test.tsx

The PR description calls out that per-metric custom formatters (currency, decimals, etc.) are intentionally skipped while a fraction mode is active, but none of the new tests pass customFormatters alongside showValuesAs to verify that.

Small addition, but would it be worth one test asserting a percent cell ignores an active customFormatters override?

@eschutho eschutho left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving — the items in my earlier comment (renderTrigger staleness for non-additive metrics, plus two test-coverage gaps) are worth a look, but I'll leave it to you whether they're blocking or fine as a follow-up.

…ion, guard non-dict JSON

Two issues flagged in review of the restore-percent-display migration:

- The migration mapped both "Sum as Fraction of X" and "Count as Fraction of
  X" onto the new value-based showValuesAs modes. Count-fraction divided a
  record count, not a metric value, so translating it would silently change
  what the chart displays (e.g. a 50/50 split by count could become 10/90 by
  value) rather than restore it. Count variants are now left un-migrated.
- params/query_context can hold malformed non-dict JSON (`[]`, `null`) from
  unrelated historical bugs; `.get()` on that raised outside the try/except
  and could abort `superset db upgrade` mid-migration after earlier batches
  already committed. Both helpers now check isinstance(..., dict) first.
Master gained a new migration (16755d4ca4ae) chaining from the same parent
(f3a8c1d2e9b7) this migration used, which the CI test-load-examples job
caught as "multiple head revisions are present". Repointed to the new true
head after merging master in.
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

🎪 Showtime is building environment on GHA for d8d8c72

Two issues in the fractionOf denominator lookup flagged in review:

- metricAxis was only captured from the first record pushed into a shared
  Total/corner slot, but `inner` (e.g. cellValue) keeps the value from the
  last record pushed. For a multi-metric chart this could point the
  denominator lookup at a different metric than the one the numerator
  value actually belongs to. metricAxis is now updated on every push so it
  stays in sync with `inner`.
- A null numerator (a DB rollup that's null, rendered blank in actual mode)
  coerced to 0 under JS's `/` operator, turning a blank cell into a
  measured 0.0% in fraction mode. `value()` now returns null in that case
  instead of dividing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

🎪 Showtime is building environment on GHA for 85760b8

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

🎪 Showtime deployed environment on GHA for d8d8c72

• Environment: http://44.244.249.18:8080 (admin/admin)
• Lifetime: 48h auto-cleanup
• Updates: New commits create fresh environments automatically

Adds the two test-coverage gaps flagged in review: a percent showValuesAs
cell whose denominator rollup level is absent from the data renders blank
instead of NaN%/Infinity%, and a percent cell ignores an active
customFormatters override rather than applying it to a ratio.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

🎪 Showtime is building environment on GHA for 1681dad

@rusackas

rusackas commented Aug 5, 2026

Copy link
Copy Markdown
Member Author

@eschutho showValuesAs already lost renderTrigger in an earlier pass so switching it forces a requery. Just pushed the two test-coverage gaps too: a missing-denominator case (renders blank, not NaN%/Infinity%) and one confirming customFormatters is ignored in percent mode.

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

🎪 Showtime deployed environment on GHA for 1681dad

• Environment: http://34.213.8.252:8080 (admin/admin)
• Lifetime: 48h auto-cleanup
• Updates: New commits create fresh environments automatically

@bito-code-review

bito-code-review Bot commented Aug 5, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #2c284c

Actionable Suggestions - 0
Review Details
  • Files reviewed - 4 · Commit Range: a2f6a55..1681dad
    • superset/migrations/versions/2026-08-05_00-00_1a27941d5352_restore_pivot_table_percent_display.py
    • tests/unit_tests/migrations/test_restore_pivot_table_percent_display.py
    • superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/utilities.ts
    • superset-frontend/plugins/plugin-chart-pivot-table/test/react-pivottable/tableRenders.test.tsx
  • Files skipped - 1
    • UPDATING.md - Reason: Filter setting
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • Eslint (Linter) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:frontend Requires changing the frontend plugins preset-io risk:db-migration PRs that require a DB migration size/XXL viz:charts:pivot Related to the Pivot Table charts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants