gkhnelbstn opened a new issue, #42701:
URL: https://github.com/apache/superset/issues/42701

   ## 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
   
   1. Create an `echarts_timeseries_bar` chart with 2+ metrics (e.g. custom SQL 
metrics `A`, `B`), Stacked, "Only Total" enabled.
   2. 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)` labeled `Sort`, used purely so `X-Axis Sort By` can 
order categories by their natural sequence instead of alphabetically. The 
generated query becomes roughly:
      ```sql
      SELECT category, A, B, MIN(some_sequence_column) AS "Sort"
      FROM ...
      GROUP BY category
      ORDER BY "Sort"
      ```
   3. A real returned row looks like: `{"category": "1-3g", "A": 32, "B": 0, 
"Sort": 2}`.
   4. The chart correctly shows only 2 series in the legend (`A`, `B`) — `Sort` 
is excluded from the rendered series.
   5. **Bug**: the "Only Total" stacked label for this category shows `34` (`32 
+ 0 + 2`) instead of the correct `32` (`32 + 0`). The sort metric's value 
silently leaks into the total.
   
   ## Root cause
   
   `plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts`:
   
   ```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`:
   
   ```ts
   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:
   
   ```ts
   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


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to