diff --git a/src/plugins/d3/renderer/components/AxisX.tsx b/src/plugins/d3/renderer/components/AxisX.tsx
index 17cdade3..f070dbc3 100644
--- a/src/plugins/d3/renderer/components/AxisX.tsx
+++ b/src/plugins/d3/renderer/components/AxisX.tsx
@@ -1,6 +1,6 @@
 import React from 'react';
 import {axisBottom, select} from 'd3';
-import type {AxisScale, AxisDomain, Selection} from 'd3';
+import type {AxisScale, AxisDomain} from 'd3';
 
 import {block} from '../../../../utils/cn';
 
@@ -17,26 +17,6 @@ type Props = {
     scale: ChartScale;
 };
 
-// Note: this method do not prepared for rotated labels
-const removeOverlappingXTicks = (axis: Selection<SVGGElement, unknown, null, undefined>) => {
-    const a = axis.selectAll('g.tick').nodes();
-
-    if (a.length <= 1) {
-        return;
-    }
-
-    for (let i = 0, x = 0; i < a.length; i++) {
-        const node = a[i] as Element;
-        const r = node.getBoundingClientRect();
-
-        if (r.left < x) {
-            node?.parentNode?.removeChild(node);
-        } else {
-            x = r.right + EMPTY_SPACE_BETWEEN_LABELS;
-        }
-    }
-};
-
 // FIXME: add overflow ellipsis for the labels that out of boundaries
 export const AxisX = ({axis, width, height, scale}: Props) => {
     const ref = React.useRef<SVGGElement>(null);
@@ -102,7 +82,20 @@ export const AxisX = ({axis, width, height, scale}: Props) => {
                 .text(axis.title.text);
         }
 
-        removeOverlappingXTicks(svgElement);
+        let elementX = 0;
+        svgElement
+            .selectAll('.tick')
+            .filter(function () {
+                const node = this as unknown as Element;
+                const r = node.getBoundingClientRect();
+
+                if (r.left < elementX) {
+                    return true;
+                }
+                elementX = r.right + EMPTY_SPACE_BETWEEN_LABELS;
+                return false;
+            })
+            .remove();
     }, [axis, width, height, scale]);
 
     return <g ref={ref} />;
diff --git a/src/plugins/d3/renderer/hooks/useAxisScales/index.ts b/src/plugins/d3/renderer/hooks/useAxisScales/index.ts
index 72bc7852..b57d48ff 100644
--- a/src/plugins/d3/renderer/hooks/useAxisScales/index.ts
+++ b/src/plugins/d3/renderer/hooks/useAxisScales/index.ts
@@ -44,17 +44,16 @@ const filterCategoriesByVisibleSeries = (args: {
 }) => {
     const {axisDirection, categories, series} = args;
 
-    return categories.filter((category) => {
-        return series.some((s) => {
-            return (
-                isSeriesWithCategoryValues(s) &&
-                s.data.some((d) => {
-                    const dataCategory = getDataCategoryValue({axisDirection, categories, data: d});
-                    return dataCategory === category;
-                })
-            );
-        });
+    const visibleCategories = new Set();
+    series.forEach((s) => {
+        if (isSeriesWithCategoryValues(s)) {
+            s.data.forEach((d) => {
+                visibleCategories.add(getDataCategoryValue({axisDirection, categories, data: d}));
+            });
+        }
     });
+
+    return categories.filter((c) => visibleCategories.has(c));
 };
 
 const createScales = (args: Args) => {
diff --git a/src/plugins/d3/renderer/hooks/useShapes/scatter.tsx b/src/plugins/d3/renderer/hooks/useShapes/scatter.tsx
index 99a2ddae..54bbc17a 100644
--- a/src/plugins/d3/renderer/hooks/useShapes/scatter.tsx
+++ b/src/plugins/d3/renderer/hooks/useShapes/scatter.tsx
@@ -88,18 +88,19 @@ export function ScatterSeriesShape(props: ScatterSeriesShapeProps) {
         }
 
         const svgElement = select(ref.current);
-        svgElement.selectAll('*').remove();
         const preparedData =
             xAxis.type === 'category' || yAxis[0]?.type === 'category'
                 ? series.data
                 : prepareLinearScatterData(series.data);
 
         svgElement
-            .selectAll('allPoints')
+            .selectAll('circle')
             .data(preparedData)
-            .enter()
-            .append('circle')
-            .attr('class', b('point'))
+            .join(
+                (enter) => enter.append('circle').attr('class', b('point')),
+                (update) => update,
+                (exit) => exit.remove(),
+            )
             .attr('fill', (d) => d.color || series.color || '')
             .attr('r', (d) => d.radius || DEFAULT_SCATTER_POINT_RADIUS)
             .attr('cx', (d) => getCxAttr({point: d, xAxis, xScale}))