Repository navigation
Timeseries Bar: stacked 'Only Total' sum includes the series-limit/sort metric's value, not just the displayed metrics #42701
Description
Summary
On a stacked Timeseries Bar chart (echarts_timeseries_bar) with "Show Total"/"Only Total" enabled, the displayed stacked total is silently inflated when the chart also uses a timeseries_limit_metric (the "Sort by" metric used to order/limit the x-axis) that isn't one of the chart's displayed metrics. The sort metric's value gets summed into the total even though it's correctly excluded from the actual rendered series/legend.
Reproduction
- Create an
echarts_timeseries_barchart with 2+ metrics (e.g. custom SQL metricsA,B), Stacked, "Only Total" enabled. - Set Sort Series By / Series limit sort by (
timeseries_limit_metric) to a metric that is not among the displayed metrics — e.g.MIN(some_sequence_column)labeledSort, used purely soX-Axis Sort Bycan order categories by their natural sequence instead of alphabetically. The generated query becomes roughly:SELECT category, A, B, MIN(some_sequence_column) AS "Sort" FROM ... GROUP BY category ORDER BY "Sort"
- A real returned row looks like:
{"category": "1-3g", "A": 32, "B": 0, "Sort": 2}. - The chart correctly shows only 2 series in the legend (
A,B) —Sortis excluded from the rendered series. - Bug: the "Only Total" stacked label for this category shows
34(32 + 0 + 2) instead of the correct32(32 + 0). The sort metric's value silently leaks into the total.
Root cause
plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts:
const { totalStackedValues, thresholdValues } = extractDataTotalValues(
rebasedData,
{ stack, percentageThreshold, xAxisCol: xAxisLabel, legendState },
);
const extraMetricLabels = extractExtraMetrics(chartProps.rawFormData).map(getMetricLabel);extraMetricLabels — which correctly excludes series-limit/sort-only metrics when building the actual chart series via extractSeries — is computed after extractDataTotalValues runs, and is never passed into it.
plugins/plugin-chart-echarts/src/utils/series.ts, extractDataTotalValues:
export function extractDataTotalValues(
data: DataRecord[],
opts: { stack: StackType; percentageThreshold: number; xAxisCol: string; legendState?: LegendState },
): { totalStackedValues: number[]; thresholdValues: number[] } {
...
data.forEach(datum => {
const values = Object.keys(datum).reduce((prev, curr) => {
if (curr === xAxisCol) return prev;
if (legendState && !legendState[curr]) return prev;
const value = datum[curr] || 0;
return prev + (value as number);
}, 0);
...
});It sums every remaining numeric key in each row. The only exclusions are the x-axis column and legend-toggled-off series — there's no way to exclude a metric that was added to the query purely for sorting/limiting (via extractExtraMetrics in buildQuery.ts, comment: // only add series limit metric if it's explicitly needed e.g. for sorting). Since that column is never a visible legend entry, legendState can never exclude it either.
Suggested fix
Thread extraMetricLabels into extractDataTotalValues and exclude them the same way xAxisCol is excluded:
export function extractDataTotalValues(
data: DataRecord[],
opts: {
stack: StackType;
percentageThreshold: number;
xAxisCol: string;
legendState?: LegendState;
extraMetricLabels?: string[]; // NEW
},
): { totalStackedValues: number[]; thresholdValues: number[] } {
const { stack, percentageThreshold, xAxisCol, legendState, extraMetricLabels } = opts;
const excludedKeys = new Set([xAxisCol, ...(extraMetricLabels ?? [])]);
...
data.forEach(datum => {
const values = Object.keys(datum).reduce((prev, curr) => {
if (excludedKeys.has(curr)) return prev;
if (legendState && !legendState[curr]) return prev;
...And in transformProps.ts, move the extraMetricLabels computation above the extractDataTotalValues call and pass it through via opts.
Impact
Any stacked Timeseries Bar/Area chart combining "Only Total"/"Show Total" with a timeseries_limit_metric that differs from the displayed metrics will show an inflated, incorrect stacked total. This is easy to hit in practice: timeseries_limit_metric is the standard way to control x-axis category ordering when the natural order isn't alphabetical (e.g. binned/bucketed labels like 1-3d, 4-6d, 7-9d, 10-12d, ...), which is precisely the situation where the sort metric is likely to differ from the displayed metrics.
Workaround
Avoid combining a timeseries_limit_metric that isn't a displayed metric with "Only Total"/"Show Total" on a stacked chart. If category ordering is the only reason for the extra metric, consider instead encoding the sort order directly into the x-axis column's values (e.g. zero-padded numeric prefixes) so X-Axis Sort By can use simple name/alphabetical ordering without needing a separate sort metric at all.
Environment
- Superset version: 6.1.0 (confirmed present at
refs/tags/6.1.0) - Chart type:
echarts_timeseries_bar(Time-series Bar Chart), stacked, "Only Total" enabled
Activity
rusackas commentedon Aug 4, 2026
Looks like you already have a fix proposed... would you want to open a PR?
rusackas commentedon Aug 9, 2026
OMG, four PRs opened? That has to be a first. I'll see if I can pick a winner.