codeant-ai-for-open-source[bot] commented on code in PR #39012:
URL: https://github.com/apache/superset/pull/39012#discussion_r3023838034


##########
superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts:
##########
@@ -682,9 +685,21 @@ export default function transformProps(
 
   // For horizontal bar charts, set max/min from calculated data bounds
   if (shouldCalculateDataBounds) {
-    // Set max to actual data max to avoid gaps and ensure labels are visible
-    if (dataMax !== undefined && yAxisMax === undefined) {
-      yAxisMax = dataMax;
+    // For stacked charts, use the max stacked total to avoid clipping bars;
+    // for non-stacked charts, use the individual series max.
+    const effectiveDataMax = stack
+      ? Math.max(
+          ...sortedTotalValues.filter(
+            (v): v is number => typeof v === 'number' && !Number.isNaN(v),
+          ),
+        )

Review Comment:
   **Suggestion:** The new stacked-axis max uses `sortedTotalValues` directly, 
but those totals are algebraic sums per row. In mixed-sign stacks (positive + 
negative values), positives and negatives cancel out, so the computed max can 
become much smaller than the actual positive bar extent and clip stacked bars. 
Compute the stacked max, then clamp it against `dataMax` so cancellation cannot 
shrink the axis range below the largest visible segment. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ❌ Horizontal stacked bar with mixed signs mis-scales axis.
   - ❌ Positive segments may render clipped or truncated.
   - ⚠️ Affects `echarts_timeseries_bar` with truncate Y-axis.
   ```
   </details>
   
   ```suggestion
       const stackedTotalMax = Math.max(
         ...sortedTotalValues.filter(
           (v): v is number => typeof v === 'number' && !Number.isNaN(v),
         ),
       );
       const effectiveDataMax = stack
         ? Math.max(dataMax ?? Number.NEGATIVE_INFINITY, stackedTotalMax)
   ```
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Render an `echarts_timeseries_bar` chart with horizontal orientation and 
stacking
   enabled so that `orientation === OrientationType.Horizontal`, `seriesType ===
   EchartsTimeseriesSeriesType.Bar`, `stack === StackControlsValue.Stack`, and 
`truncateYAxis
   === true` in `transformProps`
   
(`superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts`,
 around
   lines 122–127 and 156–160), e.g. using the same `ChartProps` pattern as in
   `test/Timeseries/Bar/transformProps.test.ts:51–58` but with `orientation: 
'horizontal'`,
   `stack: StackControlsValue.Stack`, and `truncateYAxis: true`.
   
   2. Ensure the query result (`queriesData[0].data`) contains rows with 
mixed-sign stacked
   values, e.g. fields `A = 100` and `B = -80` in the same row; 
`transformProps` receives
   this data and calls `extractDataTotalValues` at
   `superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts:17–46`, 
which computes
   `totalStackedValues` by summing all non-x-axis fields algebraically (`value 
= datum[curr]
   || 0; return prev + (value as number);`), so a row like `A=100, B=-80` 
yields a total of
   `20`.
   
   3. `transformProps` then calls `extractSeries` at `utils/series.ts:61–99` 
with
   `totalStackedValues`, and the returned `sortedTotalValues` (the per-row 
totals) are passed
   back into `transformProps` (`Timeseries/transformProps.ts:60–75`). In the 
same function,
   `dataMax` is computed from individual series values (not totals) in the loop 
at
   `Timeseries/transformProps.ts:130–173`, so `dataMax` correctly reflects the 
largest
   positive segment (e.g. `100` from `A`).
   
   4. When `shouldCalculateDataBounds` is true, the axis bounds logic at
   `Timeseries/transformProps.ts:168–185` computes `effectiveDataMax` for 
stacked charts as
   `Math.max(...sortedTotalValues.filter(...))`, ignoring `dataMax`. For a 
mixed-sign row
   where the algebraic total is small (e.g. `20`) but one positive segment is 
large (e.g.
   `100`), `effectiveDataMax` becomes `20`, and because `yAxisMax` is set to 
this value, the
   resulting swapped horizontal axis cannot accommodate the full positive bar. 
ECharts
   receives an axis max below the largest positive segment, and the positive 
portion of the
   stacked bar is visibly clipped in the rendered horizontal stacked bar chart.
   ```
   </details>
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts
   **Line:** 690:695
   **Comment:**
        *Logic Error: The new stacked-axis max uses `sortedTotalValues` 
directly, but those totals are algebraic sums per row. In mixed-sign stacks 
(positive + negative values), positives and negatives cancel out, so the 
computed max can become much smaller than the actual positive bar extent and 
clip stacked bars. Compute the stacked max, then clamp it against `dataMax` so 
cancellation cannot shrink the axis range below the largest visible segment.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F39012&comment_hash=b95888701321110283ed0e482fb0b1baed38b355f33ec8f43019dad1e4957d81&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F39012&comment_hash=b95888701321110283ed0e482fb0b1baed38b355f33ec8f43019dad1e4957d81&reaction=dislike'>👎</a>



-- 
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