You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@superset.apache.org by "sadpandajoe (via GitHub)" <gi...@apache.org> on 2026/08/29 03:20:18 UTC

[PR] fix(echarts): prevent x-axis time labels from overlapping [superset]

sadpandajoe opened a new pull request, #43669:
URL: https://github.com/apache/superset/pull/43669

   ### SUMMARY
   
   On a time-series chart with the default configuration (0° x-axis label rotation, a resolved time
   grain), ECharts' native label-collision suppression (`axisLabel.hideOverlap`) is disabled. This is a
   deliberate trade-off from a prior fix that guarantees the forced boundary/max date label is never
   hidden by ECharts' own overlap detection, but it has the side effect of disabling overlap suppression
   for every other tick on the axis too — so dense/closely-spaced time labels can render on top of each
   other instead of being thinned or spaced out.
   
   This adds label-level overlap suppression instead of touching the axis-level toggle: a shared
   `createSpacedXAxisFormatter` + `getXAxisDomain` pair (`utils/formatters.ts`) estimates each label's
   rendered pixel footprint against the available per-tick spacing and blanks a label that would
   visually collide with the previously-rendered one, while always keeping the forced boundary labels
   visible. `axisLabel.hideOverlap` stays `false` and the existing boundary-label regression tests are
   untouched.
   
   Applied identically to `Timeseries` and `MixedTimeseries`, replacing the previously duplicated inline
   formatter logic in each (which only deduplicated exact string-duplicate labels, not visually-colliding
   ones).
   
   ### BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
   
   N/A — this is a label-density/formatter fix validated by unit and integration tests; no manual
   screenshots were captured.
   
   ### TESTING INSTRUCTIONS
   
   ```bash
   cd superset-frontend
   npm run test -- plugins/plugin-chart-echarts/test
   ```
   
   New regression tests reproduce dense/closely-spaced time labels for both `Timeseries` and
   `MixedTimeseries` (confirmed RED before the fix, GREEN after). Full `plugin-chart-echarts` suite:
   994/994 passing.
   
   Manually: create a time-series chart (Line/Area/Bar) with a temporal x-axis and a time grain fine
   enough relative to the selected date range that many points/ticks land close together (e.g. Day grain
   over several months), leave X-Axis Label Rotation at its default (0°) — x-axis labels no longer
   overlap, and the first/last date labels remain visible.
   
   ### ADDITIONAL INFORMATION
   
   - [ ] Has associated issue:
   - [ ] Required feature flags:
   - [x] Changes UI
   - [ ] Includes DB Migration (follow approval process in [SIP-59](https://github.com/apache/superset/issues/13351))
     - [ ] Migration is atomic, supports rollback & is backwards-compatible
     - [ ] Confirm DB migration upgrade and downgrade tested
     - [ ] Runtime estimates and downtime expectations provided
   - [ ] Introduces new feature or API
   - [ ] Removes existing feature or API
   


-- 
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: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] fix(echarts): prevent x-axis time labels from overlapping [superset]

Posted by "netlify[bot] (via GitHub)" <gi...@apache.org>.
netlify[bot] commented on PR #43669:
URL: https://github.com/apache/superset/pull/43669#issuecomment-5481271983

   ### <span aria-hidden="true">✅</span> Deploy Preview for *superset-docs-preview* ready!
   
   
   |  Name | Link |
   |:-:|------------------------|
   |<span aria-hidden="true">🔨</span> Latest commit | a516f57104ba0a979eaae8a74c39875f595947d2 |
   |<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/projects/superset-docs-preview/deploys/6a95aa9bc557f50008172d0c |
   |<span aria-hidden="true">😎</span> Deploy Preview | [https://deploy-preview-43669--superset-docs-preview.netlify.app](https://deploy-preview-43669--superset-docs-preview.netlify.app) |
   |<span aria-hidden="true">📱</span> Preview on mobile | <details><summary> Toggle QR Code... </summary><br /><br />![QR Code](https://app.netlify.com/qr-code/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL2RlcGxveS1wcmV2aWV3LTQzNjY5LS1zdXBlcnNldC1kb2NzLXByZXZpZXcubmV0bGlmeS5hcHAifQ.pNG57bGSdnl52ESocCSF9uytRxF-AtsgJIW8ugQ0DGc)<br /><br />_Use your smartphone camera to open QR code link._</details> |
   |<span aria-hidden="true">🤖</span> Make changes | [Run an agent on this branch](https://app.netlify.com/projects/superset-docs-preview/agent-runs#DcpBCoAgEADAv-w5YY1M7Qc9Y12NAkuxCCP6e97mMC_kkvZ8wQTQgSt08Np8spDSohlEpbqdIpILUaQ7lEi5RR9yTM_sWx3JKiLrWCm9KEQ0UvceGb4f) |
   ---
   <!-- [superset-docs-preview Preview](https://deploy-preview-43669--superset-docs-preview.netlify.app) -->
   _To edit notification comments on pull requests, go to your [Netlify project configuration](https://app.netlify.com/projects/superset-docs-preview/configuration/notifications#deploy-notifications)._


-- 
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: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] fix(echarts): prevent x-axis time labels from overlapping [superset]

Posted by "codecov[bot] (via GitHub)" <gi...@apache.org>.
codecov[bot] commented on PR #43669:
URL: https://github.com/apache/superset/pull/43669#issuecomment-5460062877

   ## [Codecov](https://app.codecov.io/gh/apache/superset/pull/43669?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) Report
   :x: Patch coverage is `97.67442%` with `1 line` in your changes missing coverage. Please review.
   :white_check_mark: Project coverage is 79.22%. Comparing base ([`c7cc22f`](https://app.codecov.io/gh/apache/superset/commit/c7cc22f4fee2715688736433eb686475f896c8de?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)) to head ([`84552d4`](https://app.codecov.io/gh/apache/superset/commit/84552d42925e3db9a15b040890be2ad16b95f3ac?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache)).
   :warning: Report is 1 commits behind head on master.
   
   | [Files with missing lines](https://app.codecov.io/gh/apache/superset/pull/43669?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | Patch % | Lines |
   |---|---|---|
   | [...ugins/plugin-chart-echarts/src/utils/formatters.ts](https://app.codecov.io/gh/apache/superset/pull/43669?src=pr&el=tree&filepath=superset-frontend%2Fplugins%2Fplugin-chart-echarts%2Fsrc%2Futils%2Fformatters.ts&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#diff-c3VwZXJzZXQtZnJvbnRlbmQvcGx1Z2lucy9wbHVnaW4tY2hhcnQtZWNoYXJ0cy9zcmMvdXRpbHMvZm9ybWF0dGVycy50cw==) | 97.56% | [1 Missing :warning: ](https://app.codecov.io/gh/apache/superset/pull/43669?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) |
   
   <details><summary>Additional details and impacted files</summary>
   
   
   
   ```diff
   @@           Coverage Diff           @@
   ##           master   #43669   +/-   ##
   =======================================
     Coverage   79.21%   79.22%           
   =======================================
     Files        2879     2879           
     Lines      166034   166039    +5     
     Branches    38405    38410    +5     
   =======================================
   + Hits       131530   131539    +9     
   + Misses      32025    32021    -4     
     Partials     2479     2479           
   ```
   
   | [Flag](https://app.codecov.io/gh/apache/superset/pull/43669/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | Coverage Δ | |
   |---|---|---|
   | [javascript](https://app.codecov.io/gh/apache/superset/pull/43669/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache) | `74.69% <97.67%> (+<0.01%)` | :arrow_up: |
   
   Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache#carryforward-flags-in-the-pull-request-comment) to find out more.
   </details>
   
   [:umbrella: View full report in Codecov by Harness](https://app.codecov.io/gh/apache/superset/pull/43669?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache).   
   :loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=apache).
   <details><summary> :rocket: New features to boost your workflow: </summary>
   
   - :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
   - :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
   </details>


-- 
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: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] fix(echarts): prevent x-axis time labels from overlapping [superset]

Posted by "codeant-ai-for-open-source[bot] (via GitHub)" <gi...@apache.org>.
codeant-ai-for-open-source[bot] commented on code in PR #43669:
URL: https://github.com/apache/superset/pull/43669#discussion_r3885616587


##########
superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts:
##########
@@ -1205,46 +1207,24 @@ export default function transformProps(
 
   // When showMaxLabel is true, ECharts may render a label at the axis
   // boundary that formats identically to the last data-point tick (e.g.
-  // "2005" appears twice with Year grain). Wrap the formatter to suppress
-  // consecutive duplicate labels.
+  // "2005" appears twice with Year grain), and hideOverlap must stay off so
+  // that forced boundary label is never suppressed (#39899). Wrap the
+  // formatter to suppress consecutive duplicate labels and to thin out
+  // labels that would otherwise visually collide, since hideOverlap can no
+  // longer do that for us.
   const showMaxLabel =
     xAxisType === AxisType.Time &&
     xAxisLabelRotation === 0 &&
     !!resolvedTimeGrain;
   const deduplicatedFormatter = showMaxLabel
-    ? (() => {
-        let lastLabel: string | undefined;
-        let lastValue: number | undefined;
-        const wrapper = (value: number | string) => {
-          // ECharts formats the labels in repeated ascending passes. Reset the
-          // dedup state when the sequence restarts so a forced boundary label
-          // (e.g. the min date) isn't blanked by the previous pass's last label
-          // when both format identically (e.g. a May-to-May range).
-          if (
-            typeof value === 'number' &&
-            lastValue !== undefined &&
-            value <= lastValue
-          ) {
-            lastLabel = undefined;
-          }
-          if (typeof value === 'number') {
-            lastValue = value;
-          }
-          const label =
-            typeof xAxisFormatter === 'function'
-              ? (xAxisFormatter as Function)(value)
-              : String(value);
-          if (label === lastLabel) {
-            return '';
-          }
-          lastLabel = label;
-          return label;
-        };
-        if (typeof xAxisFormatter === 'function' && 'id' in xAxisFormatter) {
-          (wrapper as any).id = (xAxisFormatter as any).id;
-        }
-        return wrapper;
-      })()
+    ? createSpacedXAxisFormatter(
+        xAxisFormatter,
+        ...getXAxisDomain(
+          [rebasedData as Record<string, unknown>[]],
+          xAxisLabel,
+        ),
+        Math.max(width - 2 * TIMESERIES_CONSTANTS.gridOffsetLeft, 0),
+      )

Review Comment:
   **Suggestion:** The spacing calculation assumes the plot width is the full chart width minus only the fixed 20px left and right offsets. The actual ECharts plot is further reduced by y-axis title margins, legend placement, and other padding, so this overestimates available label space and can leave labels visually overlapping when `hideOverlap` is disabled. Base the calculation on the effective grid width. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ Dense labels can overlap with left-side axis titles.
   - ⚠️ Timeseries charts use incorrect available x-axis width.
   - ⚠️ MixedTimeseries has the same approximation at lines 672-682.
   ```
   </details>
   
   [![Use CodeAnt Skill](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/use-codeant-skill-flat-v2.svg)](https://docs.codeant.ai/cli/resolve-pr-comments-skill) [![Fix in Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=e2bfd9bbdcb74104b28fd39aca5b6cde&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [![Fix in VSCode Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=e2bfd9bbdcb74104b28fd39aca5b6cde&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   <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:** 1219:1227
   **Comment:**
   	*Logic Error: The spacing calculation assumes the plot width is the full chart width minus only the fixed 20px left and right offsets. The actual ECharts plot is further reduced by y-axis title margins, legend placement, and other padding, so this overestimates available label space and can leave labels visually overlapping when `hideOverlap` is disabled. Base the calculation on the effective grid width.
   
   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.
   Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F43669&comment_hash=513d92a0a1fb761d2d6f6913ae6634d7f5ab7bca4d5b6b1e868feb0782e8714d&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F43669&comment_hash=513d92a0a1fb761d2d6f6913ae6634d7f5ab7bca4d5b6b1e868feb0782e8714d&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: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] fix(echarts): prevent x-axis time labels from overlapping [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #43669:
URL: https://github.com/apache/superset/pull/43669#issuecomment-5501407918

   **Bito Automatic Review Skipped – PR Already Merged**<br/><br/>Bito scheduled an automatic review for this pull request, but the review was skipped because this PR was merged before the review could be run.<br/>No action is needed if you didn't intend to review it. To get a review, you can type `/review` in a comment and save it


-- 
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: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] fix(echarts): prevent x-axis time labels from overlapping [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #43669:
URL: https://github.com/apache/superset/pull/43669#issuecomment-5483395569

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).
   
   <details>
   <summary>
   Bito Usage Guide
   </summary>
   
   **Commands**
         
   Type the following command in the pull request comment and save the comment.
         
   - `/review` - Manually triggers an incremental AI Review.
   - `/review full` - 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 <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands" target="_blank" rel="noopener noreferrer">documentation</a> for additional commands.
         
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings <a href="https://alpha.bito.ai/home/ai-agents/code-review-agent" target="_blank" rel="noopener noreferrer">here</a> or contact your Bito workspace admin at evan@preset.io.
         
   **Documentation & Help**
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance" target="_blank" rel="noopener noreferrer">Customize agent settings</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules" target="_blank" rel="noopener noreferrer">Review rules</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent" target="_blank" rel="noopener noreferrer">General documentation</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs" target="_blank" rel="noopener noreferrer">FAQ</a>
   
   </details>
   


-- 
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: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] fix(echarts): prevent x-axis time labels from overlapping [superset]

Posted by "codeant-ai-for-open-source[bot] (via GitHub)" <gi...@apache.org>.
codeant-ai-for-open-source[bot] commented on code in PR #43669:
URL: https://github.com/apache/superset/pull/43669#discussion_r3885618812


##########
superset-frontend/plugins/plugin-chart-echarts/src/utils/formatters.ts:
##########
@@ -213,3 +215,105 @@ export function getXAxisFormatter(
   }
   return String;
 }
+
+type XAxisFormatterFn =
+  | TimeFormatter
+  | NumberFormatter
+  | StringConstructor
+  | ((value: number | string) => string);
+
+/**
+ * Wraps an x-axis time formatter so that:
+ * - consecutive ticks that format to identical text are blanked (e.g. the
+ *   boundary label forced by showMaxLabel duplicating the last real tick).
+ * - ticks that would render close enough to visually collide with the
+ *   previously shown label are blanked, since disabling ECharts'
+ *   `hideOverlap` (required to keep the forced boundary label visible, see
+ *   #39899) also disables its native overlap suppression for every other
+ *   label on the axis.
+ *
+ * The forced axis boundary labels (domainMin/domainMax) are never blanked by
+ * the spacing check so they stay visible regardless of density.
+ */
+export function createSpacedXAxisFormatter(
+  xAxisFormatter: XAxisFormatterFn | undefined,
+  domainMin: number | undefined,
+  domainMax: number | undefined,
+  plotWidthPx: number,
+): (value: number | string) => string {
+  const pixelsPerMs =
+    domainMin !== undefined && domainMax !== undefined && domainMax > domainMin
+      ? plotWidthPx / (domainMax - domainMin)
+      : undefined;
+  let lastLabel: string | undefined;
+  let lastValue: number | undefined;
+  let lastShownValue: number | undefined;
+  const wrapper = (value: number | string) => {
+    // ECharts formats the labels in repeated ascending passes. Reset the
+    // dedup/spacing state when the sequence restarts so a forced boundary
+    // label (e.g. the min date) isn't blanked by the previous pass's state
+    // when both format identically (e.g. a May-to-May range).
+    if (
+      typeof value === 'number' &&
+      lastValue !== undefined &&
+      value <= lastValue
+    ) {
+      lastLabel = undefined;
+      lastShownValue = undefined;
+    }
+    if (typeof value === 'number') {
+      lastValue = value;
+    }
+    const label =
+      typeof xAxisFormatter === 'function'
+        ? (xAxisFormatter as Function)(value)
+        : String(value);
+    if (label === lastLabel) {
+      return '';
+    }
+    const isBoundary =
+      typeof value === 'number' && (value === domainMin || value === domainMax);
+    if (
+      !isBoundary &&
+      typeof value === 'number' &&
+      pixelsPerMs !== undefined &&
+      lastShownValue !== undefined &&
+      (value - lastShownValue) * pixelsPerMs <
+        label.length * TIMESERIES_CONSTANTS.xAxisLabelCharWidthPx +
+          TIMESERIES_CONSTANTS.xAxisLabelMinGapPx
+    ) {
+      return '';
+    }
+    lastLabel = label;
+    if (typeof value === 'number') {
+      lastShownValue = value;
+    }
+    return label;
+  };
+  if (typeof xAxisFormatter === 'function' && 'id' in xAxisFormatter) {
+    (wrapper as { id?: unknown }).id = (xAxisFormatter as { id?: unknown }).id;
+  }
+  return wrapper;
+}
+
+/**
+ * Computes the [min, max] of a temporal x-axis column across one or more
+ * data record arrays, for use with createSpacedXAxisFormatter.
+ */
+export function getXAxisDomain(
+  dataRecordArrays: Record<string, unknown>[][],
+  xAxisCol: string,
+): [number | undefined, number | undefined] {
+  let domainMin: number | undefined;
+  let domainMax: number | undefined;
+  dataRecordArrays.forEach(records => {
+    records.forEach(record => {
+      const value = record[xAxisCol];
+      if (typeof value === 'number') {
+        if (domainMin === undefined || value < domainMin) domainMin = value;
+        if (domainMax === undefined || value > domainMax) domainMax = value;
+      }
+    });

Review Comment:
   **Suggestion:** `getXAxisDomain` only recognizes numeric values, but temporal query rows can contain timestamp strings or `Date` objects. For those charts both bounds remain undefined, so `pixelsPerMs` is disabled and, because `hideOverlap` is simultaneously set to false, no overlap suppression is applied at all. Normalize temporal values to epoch milliseconds before calculating the domain. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ❌ Dense string-timestamp charts retain overlapping labels.
   - ❌ Date-valued query records bypass spacing suppression.
   - ⚠️ Timeseries and MixedTimeseries are both affected.
   ```
   </details>
   
   [![Use CodeAnt Skill](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/use-codeant-skill-flat-v2.svg)](https://docs.codeant.ai/cli/resolve-pr-comments-skill) [![Fix in Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=d13d195cc8e546298930f86d060637ca&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [![Fix in VSCode Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=d13d195cc8e546298930f86d060637ca&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   <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/utils/formatters.ts
   **Line:** 311:316
   **Comment:**
   	*Logic Error: `getXAxisDomain` only recognizes numeric values, but temporal query rows can contain timestamp strings or `Date` objects. For those charts both bounds remain undefined, so `pixelsPerMs` is disabled and, because `hideOverlap` is simultaneously set to false, no overlap suppression is applied at all. Normalize temporal values to epoch milliseconds before calculating the domain.
   
   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.
   Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F43669&comment_hash=49dd02242cae9d183670a8e9d28c2f95a3fb18eb70ce3b46bd2c6215385dfbd8&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F43669&comment_hash=49dd02242cae9d183670a8e9d28c2f95a3fb18eb70ce3b46bd2c6215385dfbd8&reaction=dislike'>👎</a>



##########
superset-frontend/plugins/plugin-chart-echarts/src/constants.ts:
##########
@@ -52,6 +52,12 @@ export const TIMESERIES_CONSTANTS = {
   microChartHeight: 60,
   // One y-axis tick per this many pixels of chart height
   yAxisPixelsPerTick: 80,
+  // Rough average glyph width (px) used to estimate whether adjacent x-axis
+  // time labels would visually collide, since the real rendered width isn't
+  // known until ECharts lays out the axis.
+  xAxisLabelCharWidthPx: 7,
+  // Minimum gap (px) to keep between adjacent x-axis time labels.
+  xAxisLabelMinGapPx: 8,

Review Comment:
   **Suggestion:** The collision threshold assumes every rendered character is exactly seven pixels wide, but the formatter is also used for localized and custom time formats. Wide glyphs or long localized month names can exceed this estimate, causing the wrapper to retain labels whose actual rendered footprints overlap; narrow glyphs can also cause valid labels to be unnecessarily removed. Use measured text width or a conservative width calculation based on the actual formatter output and font. [possible bug]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ Custom time formats can remain visually overlapped.
   - ⚠️ Localized month labels may be thinned inaccurately.
   - ⚠️ Non-overlapping labels may be unnecessarily hidden.
   ```
   </details>
   
   [![Use CodeAnt Skill](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/use-codeant-skill-flat-v2.svg)](https://docs.codeant.ai/cli/resolve-pr-comments-skill) [![Fix in Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=b1f7557945fe4d5e97293cbcb50617b4&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset) [![Fix in VSCode Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=b1f7557945fe4d5e97293cbcb50617b4&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   <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/constants.ts
   **Line:** 58:60
   **Comment:**
   	*Possible Bug: The collision threshold assumes every rendered character is exactly seven pixels wide, but the formatter is also used for localized and custom time formats. Wide glyphs or long localized month names can exceed this estimate, causing the wrapper to retain labels whose actual rendered footprints overlap; narrow glyphs can also cause valid labels to be unnecessarily removed. Use measured text width or a conservative width calculation based on the actual formatter output and font.
   
   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.
   Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F43669&comment_hash=e71b5c5c8a282cc474253a7492fe78dbe9772516c0a710905c695b03b6cbe51b&reaction=like'>👍</a> | <a href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F43669&comment_hash=e71b5c5c8a282cc474253a7492fe78dbe9772516c0a710905c695b03b6cbe51b&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: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] fix(echarts): prevent x-axis time labels from overlapping [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #43669:
URL: https://github.com/apache/superset/pull/43669#issuecomment-5460016160

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).


-- 
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: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] fix(echarts): prevent x-axis time labels from overlapping [superset]

Posted by "sadpandajoe (via GitHub)" <gi...@apache.org>.
sadpandajoe commented on code in PR #43669:
URL: https://github.com/apache/superset/pull/43669#discussion_r3896322014


##########
superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts:
##########
@@ -1205,46 +1207,24 @@ export default function transformProps(
 
   // When showMaxLabel is true, ECharts may render a label at the axis
   // boundary that formats identically to the last data-point tick (e.g.
-  // "2005" appears twice with Year grain). Wrap the formatter to suppress
-  // consecutive duplicate labels.
+  // "2005" appears twice with Year grain), and hideOverlap must stay off so
+  // that forced boundary label is never suppressed (#39899). Wrap the
+  // formatter to suppress consecutive duplicate labels and to thin out
+  // labels that would otherwise visually collide, since hideOverlap can no
+  // longer do that for us.
   const showMaxLabel =
     xAxisType === AxisType.Time &&
     xAxisLabelRotation === 0 &&
     !!resolvedTimeGrain;
   const deduplicatedFormatter = showMaxLabel
-    ? (() => {
-        let lastLabel: string | undefined;
-        let lastValue: number | undefined;
-        const wrapper = (value: number | string) => {
-          // ECharts formats the labels in repeated ascending passes. Reset the
-          // dedup state when the sequence restarts so a forced boundary label
-          // (e.g. the min date) isn't blanked by the previous pass's last label
-          // when both format identically (e.g. a May-to-May range).
-          if (
-            typeof value === 'number' &&
-            lastValue !== undefined &&
-            value <= lastValue
-          ) {
-            lastLabel = undefined;
-          }
-          if (typeof value === 'number') {
-            lastValue = value;
-          }
-          const label =
-            typeof xAxisFormatter === 'function'
-              ? (xAxisFormatter as Function)(value)
-              : String(value);
-          if (label === lastLabel) {
-            return '';
-          }
-          lastLabel = label;
-          return label;
-        };
-        if (typeof xAxisFormatter === 'function' && 'id' in xAxisFormatter) {
-          (wrapper as any).id = (xAxisFormatter as any).id;
-        }
-        return wrapper;
-      })()
+    ? createSpacedXAxisFormatter(
+        xAxisFormatter,
+        ...getXAxisDomain(
+          [rebasedData as Record<string, unknown>[]],
+          xAxisLabel,
+        ),
+        Math.max(width - 2 * TIMESERIES_CONSTANTS.gridOffsetLeft, 0),
+      )

Review Comment:
   Acknowledged — per rebenitez1802's review, this is a real but acceptable heuristic. Cheap improvement noted: swap the fixed `width - 2 * gridOffsetLeft` for the already-computed `padding.left`/`padding.right` insets. Leaving as a follow-up rather than blocking this fix.



##########
superset-frontend/plugins/plugin-chart-echarts/src/constants.ts:
##########
@@ -52,6 +52,12 @@ export const TIMESERIES_CONSTANTS = {
   microChartHeight: 60,
   // One y-axis tick per this many pixels of chart height
   yAxisPixelsPerTick: 80,
+  // Rough average glyph width (px) used to estimate whether adjacent x-axis
+  // time labels would visually collide, since the real rendered width isn't
+  // known until ECharts lays out the axis.
+  xAxisLabelCharWidthPx: 7,
+  // Minimum gap (px) to keep between adjacent x-axis time labels.
+  xAxisLabelMinGapPx: 8,

Review Comment:
   Acknowledged — per rebenitez1802's review, the fixed 7px/char estimate is a real but acceptable heuristic (worst case still beats no suppression). A measureText-based estimate would be a nice follow-up, not blocking this fix.



##########
superset-frontend/plugins/plugin-chart-echarts/src/utils/formatters.ts:
##########
@@ -213,3 +215,105 @@ export function getXAxisFormatter(
   }
   return String;
 }
+
+type XAxisFormatterFn =
+  | TimeFormatter
+  | NumberFormatter
+  | StringConstructor
+  | ((value: number | string) => string);
+
+/**
+ * Wraps an x-axis time formatter so that:
+ * - consecutive ticks that format to identical text are blanked (e.g. the
+ *   boundary label forced by showMaxLabel duplicating the last real tick).
+ * - ticks that would render close enough to visually collide with the
+ *   previously shown label are blanked, since disabling ECharts'
+ *   `hideOverlap` (required to keep the forced boundary label visible, see
+ *   #39899) also disables its native overlap suppression for every other
+ *   label on the axis.
+ *
+ * The forced axis boundary labels (domainMin/domainMax) are never blanked by
+ * the spacing check so they stay visible regardless of density.
+ */
+export function createSpacedXAxisFormatter(
+  xAxisFormatter: XAxisFormatterFn | undefined,
+  domainMin: number | undefined,
+  domainMax: number | undefined,
+  plotWidthPx: number,
+): (value: number | string) => string {
+  const pixelsPerMs =
+    domainMin !== undefined && domainMax !== undefined && domainMax > domainMin
+      ? plotWidthPx / (domainMax - domainMin)
+      : undefined;
+  let lastLabel: string | undefined;
+  let lastValue: number | undefined;
+  let lastShownValue: number | undefined;
+  const wrapper = (value: number | string) => {
+    // ECharts formats the labels in repeated ascending passes. Reset the
+    // dedup/spacing state when the sequence restarts so a forced boundary
+    // label (e.g. the min date) isn't blanked by the previous pass's state
+    // when both format identically (e.g. a May-to-May range).
+    if (
+      typeof value === 'number' &&
+      lastValue !== undefined &&
+      value <= lastValue
+    ) {
+      lastLabel = undefined;
+      lastShownValue = undefined;
+    }
+    if (typeof value === 'number') {
+      lastValue = value;
+    }
+    const label =
+      typeof xAxisFormatter === 'function'
+        ? (xAxisFormatter as Function)(value)
+        : String(value);
+    if (label === lastLabel) {
+      return '';
+    }
+    const isBoundary =
+      typeof value === 'number' && (value === domainMin || value === domainMax);
+    if (
+      !isBoundary &&
+      typeof value === 'number' &&
+      pixelsPerMs !== undefined &&
+      lastShownValue !== undefined &&
+      (value - lastShownValue) * pixelsPerMs <
+        label.length * TIMESERIES_CONSTANTS.xAxisLabelCharWidthPx +
+          TIMESERIES_CONSTANTS.xAxisLabelMinGapPx
+    ) {
+      return '';
+    }
+    lastLabel = label;
+    if (typeof value === 'number') {
+      lastShownValue = value;
+    }
+    return label;
+  };
+  if (typeof xAxisFormatter === 'function' && 'id' in xAxisFormatter) {
+    (wrapper as { id?: unknown }).id = (xAxisFormatter as { id?: unknown }).id;
+  }
+  return wrapper;
+}
+
+/**
+ * Computes the [min, max] of a temporal x-axis column across one or more
+ * data record arrays, for use with createSpacedXAxisFormatter.
+ */
+export function getXAxisDomain(
+  dataRecordArrays: Record<string, unknown>[][],
+  xAxisCol: string,
+): [number | undefined, number | undefined] {
+  let domainMin: number | undefined;
+  let domainMax: number | undefined;
+  dataRecordArrays.forEach(records => {
+    records.forEach(record => {
+      const value = record[xAxisCol];
+      if (typeof value === 'number') {
+        if (domainMin === undefined || value < domainMin) domainMin = value;
+        if (domainMax === undefined || value > domainMax) domainMax = value;
+      }
+    });

Review Comment:
   Acknowledged — per rebenitez1802's review, this looks like a false positive on the standard pipeline: the chart-data API serializes temporal columns to epoch-ms numbers, so the numeric-only filter in getXAxisDomain is correct there. Not blocking this fix.



-- 
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: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] fix(echarts): prevent x-axis time labels from overlapping [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #43669:
URL: https://github.com/apache/superset/pull/43669#issuecomment-5460402887

   <!-- Bito Reply -->
   The flagged issue is correct. The current spacing calculation uses a simplified width (`width - 2 * TIMESERIES_CONSTANTS.gridOffsetLeft`) which ignores additional ECharts layout elements like y-axis titles, legends, and padding, leading to an overestimation of available space and potential label overlap.
   
   To resolve this, you should calculate the effective grid width by accounting for these additional margins. In `transformProps.ts`, you can access these values from the chart props or ECharts configuration and subtract them from the total width before passing the value to `createSpacedXAxisFormatter`.
   
   Would you like me to fetch all other comments on this PR to validate and implement fixes for them as well?
   
   **superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts**
   ```
   Math.max(width - 2 * TIMESERIES_CONSTANTS.gridOffsetLeft, 0),
   ```


-- 
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: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] fix(echarts): prevent x-axis time labels from overlapping [superset]

Posted by "sadpandajoe (via GitHub)" <gi...@apache.org>.
sadpandajoe merged PR #43669:
URL: https://github.com/apache/superset/pull/43669


-- 
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: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org


Re: [PR] fix(echarts): prevent x-axis time labels from overlapping [superset]

Posted by "bito-code-review[bot] (via GitHub)" <gi...@apache.org>.
bito-code-review[bot] commented on PR #43669:
URL: https://github.com/apache/superset/pull/43669#issuecomment-5461107696

   AI Code Review is in progress (usually takes 3 to 15 minutes unless it's a very large PR).
   
   <details>
   <summary>
   Bito Usage Guide
   </summary>
   
   **Commands**
         
   Type the following command in the pull request comment and save the comment.
         
   - `/review` - Manually triggers an incremental AI Review.
   - `/review full` - 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 <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/available-commands" target="_blank" rel="noopener noreferrer">documentation</a> for additional commands.
         
   **Configuration**
   
   This repository uses `Superset` You can customize the agent settings <a href="https://alpha.bito.ai/home/ai-agents/code-review-agent" target="_blank" rel="noopener noreferrer">here</a> or contact your Bito workspace admin at evan@preset.io.
         
   **Documentation & Help**
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/getting-started/install-run-using-bito-cloud/create-or-customize-an-agent-instance" target="_blank" rel="noopener noreferrer">Customize agent settings</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/implementing-custom-code-review-rules" target="_blank" rel="noopener noreferrer">Review rules</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent" target="_blank" rel="noopener noreferrer">General documentation</a>
   - <a href="https://docs.bito.ai/bito-dev-agents/ai-code-review-agent/faqs" target="_blank" rel="noopener noreferrer">FAQ</a>
   
   </details>
   


-- 
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: notifications-unsubscribe@superset.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org