From dbdef76e639d3f5857f8e787d5435530f0ebaac7 Mon Sep 17 00:00:00 2001
From: Anton Kulyk <kuliks.anton@gmail.com>
Date: Wed, 23 Oct 2024 16:58:07 +0100
Subject: [PATCH] Allow grouping bar chart series into "Other" category
 (#48265)

* Add `graph.max_categories` viz setting

* Allow grouping series into "other" category

* Add tooltip

* Toggle "other" series visibility

* WIP: new implementation for `graph.series_order`

* Remove not used function

* Make "other" series a regular `SeriesModel`

* Fix stacked bar charts

* Remove colors from "other" tooltip

* Sort "other" tooltip values

* Update `graph.max_categories` setting

- negative number validation
- 0 value turns off grouping

* Fix Loki test

* Add basic loki test

* Add loki test for stacked chart

* Add loki test for stacked normalized chart

* slight refactor of series_order setting

* Add screenshots

* Handle different kinds of aggregations for "other"

* Handle different aggregation kinds in tooltips

* Add `graph.other_series_aggregation_fn` viz setting

* Fix type errors

* Fix unit tests

* settings ui

* remove sorting by value to match series order setting, other color

* hide grouped series controls

* Add e2e test

* Update screenshots

* Fix incorrect series grouping for stacked charts

* group series into other settings

* Update e2e test to work with new viz settings

* Disable drills for the "Other" series

* fix max_categories setting popover positioning

* fix total row has misaligned columns on other series values

* Remove redundant `click({ force: true })`

* Rename aggregation fn viz setting

* Move aggregation fn setting to the popover

* WIP

* Update popover

* Fix `it.only`

* Fix legend sync issue

* Disable "Other" category by default (temporary)

* Enable aggregation fn picker for MBQL queries (temporary)

* Move "Other" category summary to a tooltip row

* Add `graph.max_categories_enabled` to viz settings type

* Reuse already computed "Other" value in tooltips

* Add null check

* Fix series length check

---------

Co-authored-by: Aleksandr Lesnenko <alxnddr@gmail.com>
---
 ..._ComboChart_Bar_Max_Categories_Default.png | Bin 0 -> 18533 bytes
 ..._ComboChart_Bar_Max_Categories_Stacked.png | Bin 0 -> 14323 bytes
 ..._Bar_Max_Categories_Stacked_Normalized.png | Bin 0 -> 18349 bytes
 .../helpers/e2e-visual-tests-helpers.js       |   4 +
 .../bar_chart.cy.spec.js                      | 214 +++++-
 frontend/src/metabase-types/api/card.ts       |   9 +
 frontend/src/metabase-types/api/dataset.ts    |  15 +
 .../core/components/Sortable/SortableList.tsx |  28 +-
 .../ComboChart/ComboChart.stories.tsx         |  27 +
 .../bar-histogram-series-breakout.json        |   3 +-
 .../bar-max-categories-default.json           | 612 ++++++++++++++++++
 ...bar-max-categories-stacked-normalized.json | 606 +++++++++++++++++
 .../bar-max-categories-stacked.json           | 606 +++++++++++++++++
 .../ComboChart/stories-data/index.ts          |   6 +
 .../EChartsTooltip/EChartsTooltip.tsx         |  12 +-
 .../ClickActions/ClickActionsView.tsx         |   2 +-
 ...tNestedSettingsSeriesMultiple.unit.spec.js |   5 +-
 .../ChartSettingColorPicker.tsx               |   2 +-
 .../settings/ChartSettingColorsPicker.jsx     |   3 +
 .../settings/ChartSettingFieldPicker.jsx      |  34 +-
 .../ChartSettingFieldPicker.unit.spec.js      |   5 +-
 .../settings/ChartSettingFieldsPicker.jsx     |   2 +
 .../settings/ChartSettingInputNumeric.tsx     |   6 +-
 .../settings/ChartSettingMaxCategories.tsx    |  85 +++
 .../ChartSettingOrderedItems.tsx              |  11 +-
 .../settings/ChartSettingSeriesOrder.tsx      | 100 ++-
 .../components/settings/types.ts              |   7 +
 .../echarts/cartesian/constants/dataset.ts    |   3 +
 .../echarts/cartesian/model/dataset.ts        |  30 +-
 .../cartesian/model/dataset.unit.spec.ts      |   8 +
 .../echarts/cartesian/model/guards.ts         |   4 +-
 .../echarts/cartesian/model/index.ts          |  34 +-
 .../echarts/cartesian/model/legend.ts         |   4 +-
 .../echarts/cartesian/model/other-series.ts   | 154 +++++
 .../echarts/cartesian/model/series.ts         |   2 -
 .../echarts/cartesian/model/types.ts          |   3 +
 .../echarts/cartesian/option/index.ts         |   2 +
 .../echarts/cartesian/scatter/model/index.ts  |   1 +
 .../visualizations/lib/settings/graph.js      | 105 ++-
 .../visualizations/lib/settings/series.js     |   5 +
 .../shared/settings/cartesian-chart.ts        |   9 +
 .../visualizations/CartesianChart/events.ts   | 149 +++--
 42 files changed, 2803 insertions(+), 114 deletions(-)
 create mode 100644 .loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Max_Categories_Default.png
 create mode 100644 .loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Max_Categories_Stacked.png
 create mode 100644 .loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Max_Categories_Stacked_Normalized.png
 create mode 100644 frontend/src/metabase/static-viz/components/ComboChart/stories-data/bar-max-categories-default.json
 create mode 100644 frontend/src/metabase/static-viz/components/ComboChart/stories-data/bar-max-categories-stacked-normalized.json
 create mode 100644 frontend/src/metabase/static-viz/components/ComboChart/stories-data/bar-max-categories-stacked.json
 create mode 100644 frontend/src/metabase/visualizations/components/settings/ChartSettingMaxCategories.tsx
 create mode 100644 frontend/src/metabase/visualizations/components/settings/types.ts
 create mode 100644 frontend/src/metabase/visualizations/echarts/cartesian/model/other-series.ts

diff --git a/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Max_Categories_Default.png b/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Max_Categories_Default.png
new file mode 100644
index 0000000000000000000000000000000000000000..847a02a9ae74b2a6dc84a41dcd44af59905408f6
GIT binary patch
literal 18533
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

literal 0
HcmV?d00001

diff --git a/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Max_Categories_Stacked.png b/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Max_Categories_Stacked.png
new file mode 100644
index 0000000000000000000000000000000000000000..021f1fb51b320c4013011f6aa1666e9342989ff4
GIT binary patch
literal 14323
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
Bh%W#D

literal 0
HcmV?d00001

diff --git a/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Max_Categories_Stacked_Normalized.png b/.loki/reference/chrome_laptop_static_viz_ComboChart_Bar_Max_Categories_Stacked_Normalized.png
new file mode 100644
index 0000000000000000000000000000000000000000..a411f14425ef4e609e98c8c69d9d26eeabeaa5ff
GIT binary patch
literal 18349
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
G>3;$B`Y(k5

literal 0
HcmV?d00001

diff --git a/e2e/support/helpers/e2e-visual-tests-helpers.js b/e2e/support/helpers/e2e-visual-tests-helpers.js
index 916f0f475ac..270f46e3623 100644
--- a/e2e/support/helpers/e2e-visual-tests-helpers.js
+++ b/e2e/support/helpers/e2e-visual-tests-helpers.js
@@ -81,6 +81,10 @@ export function cartesianChartCircleWithColors(colors) {
   return colors.map(color => cartesianChartCircleWithColor(color));
 }
 
+export function otherSeriesChartPaths() {
+  return chartPathWithFillColor("#949AAB");
+}
+
 export function scatterBubbleWithColor(color) {
   return echartsContainer().find(`path[d="${CIRCLE_PATH}"][fill="${color}"]`);
 }
diff --git a/e2e/test/scenarios/visualizations-charts/bar_chart.cy.spec.js b/e2e/test/scenarios/visualizations-charts/bar_chart.cy.spec.js
index ba06be055aa..baa5338c876 100644
--- a/e2e/test/scenarios/visualizations-charts/bar_chart.cy.spec.js
+++ b/e2e/test/scenarios/visualizations-charts/bar_chart.cy.spec.js
@@ -8,13 +8,17 @@ import {
   createQuestion,
   cypressWaitAll,
   echartsContainer,
+  echartsTooltip,
   getDraggableElements,
   getValueLabels,
   leftSidebar,
   modal,
   moveDnDKitElement,
+  openNotebook,
+  otherSeriesChartPaths,
   popover,
   queryBuilderHeader,
+  queryBuilderMain,
   restore,
   sidebar,
   visitDashboard,
@@ -368,16 +372,18 @@ describe("scenarios > visualizations > bar chart", () => {
     });
 
     cy.findByTestId("viz-settings-button").click();
+    leftSidebar().button("90 more series").click();
     cy.get("[data-testid^=draggable-item]").should("have.length", 100);
 
-    // eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
-    cy.findByText("ID is less than 101").click();
-    cy.findByDisplayValue("101").type("{backspace}2");
-    // eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
-    cy.findByText("Update filter").click();
+    cy.findByTestId("qb-filters-panel")
+      .findByText("ID is less than 101")
+      .click();
+    popover().within(() => {
+      cy.findByDisplayValue("101").type("{backspace}2");
+      cy.button("Update filter").click();
+    });
 
-    // eslint-disable-next-line no-unscoped-text-selectors -- deprecated usage
-    cy.findByText(
+    queryBuilderMain().findByText(
       "This chart type doesn't support more than 100 series of data.",
     );
     cy.get("[data-testid^=draggable-item]").should("have.length", 0);
@@ -752,6 +758,200 @@ describe("scenarios > visualizations > bar chart", () => {
     });
     resetHoverState();
   });
+
+  it("should allow grouping series into a single 'Other' series", () => {
+    const AK_SERIES_COLOR = "#509EE3";
+
+    const USER_STATE_FIELD_REF = [
+      "field",
+      PEOPLE.STATE,
+      { "source-field": ORDERS.USER_ID },
+    ];
+    const ORDER_CREATED_AT_FIELD_REF = [
+      "field",
+      ORDERS.CREATED_AT,
+      { "temporal-unit": "month" },
+    ];
+
+    function setMaxCategories(value, { viaBreakoutSettings = false } = {}) {
+      if (viaBreakoutSettings) {
+        leftSidebar().findByTestId("settings-STATE").click();
+      } else {
+        leftSidebar().findByLabelText("Other series settings").click();
+      }
+      popover()
+        .findByTestId("graph-max-categories-input")
+        .type(`{selectAll}${value}`)
+        .blur();
+      cy.wait(500); // wait for viz to re-render
+    }
+
+    function setOtherCategoryAggregationFn(fnName) {
+      leftSidebar().findByLabelText("Other series settings").click();
+      popover()
+        .findByTestId("graph-other-category-aggregation-fn-picker")
+        .click();
+      popover().last().findByText(fnName).click();
+    }
+
+    visitQuestionAdhoc({
+      display: "bar",
+      dataset_query: {
+        type: "query",
+        database: SAMPLE_DB_ID,
+        query: {
+          "source-table": ORDERS_ID,
+          aggregation: [["count"]],
+          breakout: [USER_STATE_FIELD_REF, ORDER_CREATED_AT_FIELD_REF],
+          filter: [
+            "and",
+            [
+              "between",
+              ORDER_CREATED_AT_FIELD_REF,
+              "2022-09-01T00:00Z",
+              "2023-02-01T00:00Z",
+            ],
+            [
+              "=",
+              USER_STATE_FIELD_REF,
+              "AK",
+              "AL",
+              "AR",
+              "AZ",
+              "CA",
+              "CO",
+              "CT",
+              "DE",
+              "FL",
+              "GA",
+              "IA",
+              "ID",
+              "IL",
+              "KY",
+            ],
+          ],
+        },
+      },
+    });
+
+    // Enable 'Other' series
+    cy.findByTestId("viz-settings-button").click();
+    leftSidebar().findByTestId("settings-STATE").click();
+    popover().findByLabelText("Enforce maximum number of series").click();
+
+    // Test 'Other' series renders
+    otherSeriesChartPaths().should("have.length", 6);
+
+    // Test drill-through is disabled for 'Other' series
+    otherSeriesChartPaths().first().click();
+    cy.findByTestId("click-actions-view").should("not.exist");
+
+    // Test drill-through is enabled for regular series
+    chartPathWithFillColor(AK_SERIES_COLOR).first().click();
+    cy.findByTestId("click-actions-view").should("exist");
+
+    // Test legend and series visibility toggling
+    queryBuilderMain()
+      .findAllByTestId("legend-item")
+      .should("have.length", 9)
+      .last()
+      .as("other-series-legend-item");
+    cy.get("@other-series-legend-item").findByLabelText("Hide series").click();
+    otherSeriesChartPaths().should("have.length", 0);
+    cy.get("@other-series-legend-item").findByLabelText("Show series").click();
+    otherSeriesChartPaths().should("have.length", 6);
+
+    // Test tooltips
+    chartPathWithFillColor(AK_SERIES_COLOR).first().realHover();
+    assertEChartsTooltip({ rows: [{ name: "Other", value: "9" }] });
+    otherSeriesChartPaths().first().realHover();
+    assertEChartsTooltip({
+      header: "September 2022",
+      rows: [
+        { name: "IA", value: "3" },
+        { name: "KY", value: "2" },
+        { name: "FL", value: "1" },
+        { name: "GA", value: "1" },
+        { name: "ID", value: "1" },
+        { name: "IL", value: "1" },
+        { name: "Total", value: "9" },
+      ],
+    });
+
+    // Test "graph.max_categories" change
+    setMaxCategories(4);
+    queryBuilderMain().click(); // close popover
+    chartPathWithFillColor(AK_SERIES_COLOR).first().realHover();
+    echartsTooltip().find("tr").should("have.length", 5);
+    queryBuilderMain().findAllByTestId("legend-item").should("have.length", 5);
+
+    // Test can move series in/out of "Other" series
+    moveDnDKitElement(getDraggableElements().eq(3), { vertical: 150 }); // Move AZ into "Other"
+    moveDnDKitElement(getDraggableElements().eq(6), { vertical: -150 }); // Move CT out of "Other"
+
+    queryBuilderMain().findAllByTestId("legend-item").should("have.length", 5);
+    queryBuilderMain()
+      .findAllByTestId("legend-item")
+      .contains("AZ")
+      .should("not.exist");
+    queryBuilderMain()
+      .findAllByTestId("legend-item")
+      .contains("CT")
+      .should("exist");
+
+    // Test "graph.max_categories" removes "Other" altogether
+    setMaxCategories(0);
+    chartPathWithFillColor(AK_SERIES_COLOR).first().realHover();
+    echartsTooltip().find("tr").should("have.length", 14);
+    queryBuilderMain().findAllByTestId("legend-item").should("have.length", 14);
+    otherSeriesChartPaths().should("not.exist");
+    setMaxCategories(8, { viaBreakoutSettings: true });
+
+    // Test "graph.other_category_aggregation_fn" for native queries
+    openNotebook();
+    queryBuilderHeader().button("View the SQL").click();
+    cy.findByTestId("native-query-preview-sidebar")
+      .button("Convert this question to SQL")
+      .click();
+    cy.wait("@dataset");
+    queryBuilderMain().findByTestId("visibility-toggler").click();
+
+    cy.findByTestId("viz-settings-button").click();
+    setOtherCategoryAggregationFn("Average");
+
+    chartPathWithFillColor(AK_SERIES_COLOR).first().realHover();
+    assertEChartsTooltip({ rows: [{ name: "Other", value: "1.5" }] });
+
+    otherSeriesChartPaths().first().realHover();
+    assertEChartsTooltip({
+      header: "September 2022",
+      rows: [
+        { name: "IA", value: "3" },
+        { name: "KY", value: "2" },
+        { name: "FL", value: "1" },
+        { name: "GA", value: "1" },
+        { name: "ID", value: "1" },
+        { name: "IL", value: "1" },
+        { name: "Average", value: "1.5" },
+      ],
+    });
+
+    setOtherCategoryAggregationFn("Min");
+
+    chartPathWithFillColor(AK_SERIES_COLOR).first().realHover();
+    assertEChartsTooltip({ rows: [{ name: "Other", value: "1" }] });
+
+    otherSeriesChartPaths().first().realHover();
+    assertEChartsTooltip({ rows: [{ name: "Min", value: "1" }] });
+
+    setOtherCategoryAggregationFn("Max");
+
+    chartPathWithFillColor(AK_SERIES_COLOR).first().realHover();
+    assertEChartsTooltip({ rows: [{ name: "Other", value: "3" }] });
+
+    otherSeriesChartPaths().first().realHover();
+    assertEChartsTooltip({ rows: [{ name: "Max", value: "3" }] });
+  });
 });
 
 function resetHoverState() {
diff --git a/frontend/src/metabase-types/api/card.ts b/frontend/src/metabase-types/api/card.ts
index b2e07251539..babfb5c17ef 100644
--- a/frontend/src/metabase-types/api/card.ts
+++ b/frontend/src/metabase-types/api/card.ts
@@ -151,6 +151,15 @@ export type VisualizationSettings = {
   "graph.show_values"?: boolean;
   "stackable.stack_type"?: StackType;
   "graph.show_stack_values"?: StackValuesDisplay;
+  "graph.max_categories_enabled"?: boolean;
+  "graph.max_categories"?: number;
+  "graph.other_category_aggregation_fn"?:
+    | "sum"
+    | "avg"
+    | "min"
+    | "max"
+    | "stddev"
+    | "median";
 
   // Table
   "table.columns"?: TableColumnOrderSetting[];
diff --git a/frontend/src/metabase-types/api/dataset.ts b/frontend/src/metabase-types/api/dataset.ts
index 51e7801e792..a6125b49b1e 100644
--- a/frontend/src/metabase-types/api/dataset.ts
+++ b/frontend/src/metabase-types/api/dataset.ts
@@ -18,6 +18,18 @@ export type BinningMetadata = {
   num_bins?: number;
 };
 
+export type AggregationType =
+  | "count"
+  | "sum"
+  | "cum-sum"
+  | "cum-count"
+  | "distinct"
+  | "min"
+  | "max"
+  | "avg"
+  | "median"
+  | "stddev";
+
 export interface DatasetColumn {
   id?: FieldId;
   name: string;
@@ -25,6 +37,9 @@ export interface DatasetColumn {
   description?: string | null;
   source: string;
   aggregation_index?: number;
+
+  aggregation_type?: AggregationType;
+
   coercion_strategy?: string | null;
   visibility_type?: FieldVisibilityType;
   table_id?: TableId;
diff --git a/frontend/src/metabase/core/components/Sortable/SortableList.tsx b/frontend/src/metabase/core/components/Sortable/SortableList.tsx
index eb69a9e1416..91c72702d14 100644
--- a/frontend/src/metabase/core/components/Sortable/SortableList.tsx
+++ b/frontend/src/metabase/core/components/Sortable/SortableList.tsx
@@ -6,12 +6,17 @@ import type {
 } from "@dnd-kit/core";
 import { DndContext, DragOverlay } from "@dnd-kit/core";
 import { SortableContext, arrayMove } from "@dnd-kit/sortable";
-import { useEffect, useMemo, useState } from "react";
+import React, { useEffect, useMemo, useState } from "react";
 import _ from "underscore";
 
 import GrabberS from "metabase/css/components/grabber.module.css";
 import { isNotNull } from "metabase/lib/types";
 
+export type SortableDivider = {
+  afterIndex: number;
+  renderFn: () => React.ReactNode;
+};
+
 type ItemId = number | string;
 export type DragEndEvent = {
   id: ItemId;
@@ -37,6 +42,7 @@ type SortableListProps<T> = {
   sensors?: SensorDescriptor<any>[];
   modifiers?: Modifier[];
   useDragOverlay?: boolean;
+  dividers?: SortableDivider[];
 };
 
 export const SortableList = <T,>({
@@ -48,6 +54,7 @@ export const SortableList = <T,>({
   sensors = [],
   modifiers = [],
   useDragOverlay = true,
+  dividers,
 }: SortableListProps<T>) => {
   const [itemIds, setItemIds] = useState<ItemId[]>([]);
   const [indexedItems, setIndexedItems] = useState<Partial<Record<ItemId, T>>>(
@@ -55,6 +62,13 @@ export const SortableList = <T,>({
   );
   const [activeItem, setActiveItem] = useState<T | null>(null);
 
+  const dividersByIndex = useMemo(() => {
+    return (dividers ?? []).reduce((acc, item) => {
+      acc.set(item.afterIndex, item);
+      return acc;
+    }, new Map<number, SortableDivider>());
+  }, [dividers]);
+
   useEffect(() => {
     setItemIds(items.map(getId));
     setIndexedItems(_.indexBy(items, getId));
@@ -63,14 +77,20 @@ export const SortableList = <T,>({
   const sortableElements = useMemo(
     () =>
       itemIds
-        .map(id => {
+        .map((id, index) => {
           const item = indexedItems[id];
+          const divider = dividersByIndex.get(index);
           if (item) {
-            return renderItem({ item, id });
+            return (
+              <React.Fragment key={id}>
+                {divider ? divider.renderFn() : null}
+                {renderItem({ item, id })}
+              </React.Fragment>
+            );
           }
         })
         .filter(isNotNull),
-    [itemIds, renderItem, indexedItems],
+    [itemIds, indexedItems, dividersByIndex, renderItem],
   );
 
   const handleDragOver = ({ active, over }: DragOverEvent) => {
diff --git a/frontend/src/metabase/static-viz/components/ComboChart/ComboChart.stories.tsx b/frontend/src/metabase/static-viz/components/ComboChart/ComboChart.stories.tsx
index f99d70299bd..80f820e9668 100644
--- a/frontend/src/metabase/static-viz/components/ComboChart/ComboChart.stories.tsx
+++ b/frontend/src/metabase/static-viz/components/ComboChart/ComboChart.stories.tsx
@@ -973,6 +973,33 @@ export const BarStackedAllLabelsTimeseriesWithGap45717 = {
   },
 };
 
+export const BarMaxCategoriesDefault = {
+  render: Template,
+
+  args: {
+    rawSeries: data.barMaxCategoriesDefault as any,
+    renderingContext,
+  },
+};
+
+export const BarMaxCategoriesStacked = {
+  render: Template,
+
+  args: {
+    rawSeries: data.barMaxCategoriesStacked as any,
+    renderingContext,
+  },
+};
+
+export const BarMaxCategoriesStackedNormalized = {
+  render: Template,
+
+  args: {
+    rawSeries: data.barMaxCategoriesStackedNormalized as any,
+    renderingContext,
+  },
+};
+
 export const OffsetBasedTimezone47835 = {
   render: Template,
   args: {
diff --git a/frontend/src/metabase/static-viz/components/ComboChart/stories-data/bar-histogram-series-breakout.json b/frontend/src/metabase/static-viz/components/ComboChart/stories-data/bar-histogram-series-breakout.json
index 733b3873499..d771e36ea13 100644
--- a/frontend/src/metabase/static-viz/components/ComboChart/stories-data/bar-histogram-series-breakout.json
+++ b/frontend/src/metabase/static-viz/components/ComboChart/stories-data/bar-histogram-series-breakout.json
@@ -28,7 +28,8 @@
         "graph.series_order": null,
         "graph.x_axis.scale": "histogram",
         "stackable.stack_type": null,
-        "graph.metrics": ["count"]
+        "graph.metrics": ["count"],
+        "graph.max_categories": 0
       },
       "last-edit-info": {
         "id": 1,
diff --git a/frontend/src/metabase/static-viz/components/ComboChart/stories-data/bar-max-categories-default.json b/frontend/src/metabase/static-viz/components/ComboChart/stories-data/bar-max-categories-default.json
new file mode 100644
index 00000000000..fe50cdadb55
--- /dev/null
+++ b/frontend/src/metabase/static-viz/components/ComboChart/stories-data/bar-max-categories-default.json
@@ -0,0 +1,612 @@
+[
+  {
+    "card": {
+      "cache_invalidated_at": null,
+      "description": null,
+      "archived": false,
+      "view_count": 150,
+      "collection_position": null,
+      "source_card_id": null,
+      "table_id": 5,
+      "can_run_adhoc_query": true,
+      "result_metadata": [
+        {
+          "description": "The state or province of the account’s billing address",
+          "database_type": "CHARACTER",
+          "semantic_type": "type/State",
+          "table_id": 3,
+          "coercion_strategy": null,
+          "name": "STATE",
+          "settings": null,
+          "source": "breakout",
+          "fk_target_field_id": null,
+          "fk_field_id": 43,
+          "field_ref": [
+            "field",
+            48,
+            {
+              "base-type": "type/Text",
+              "source-field": 43
+            }
+          ],
+          "effective_type": "type/Text",
+          "nfc_path": null,
+          "parent_id": null,
+          "id": 48,
+          "position": 7,
+          "visibility_type": "normal",
+          "display_name": "User → State",
+          "fingerprint": {
+            "global": {
+              "distinct-count": 49,
+              "nil%": 0.0
+            },
+            "type": {
+              "type/Text": {
+                "percent-json": 0.0,
+                "percent-url": 0.0,
+                "percent-email": 0.0,
+                "percent-state": 1.0,
+                "average-length": 2.0
+              }
+            }
+          },
+          "base_type": "type/Text",
+          "source_alias": "PEOPLE__via__USER_ID"
+        },
+        {
+          "description": "The date and time an order was submitted.",
+          "database_type": "TIMESTAMP",
+          "semantic_type": "type/CreationTimestamp",
+          "table_id": 5,
+          "coercion_strategy": null,
+          "unit": "month",
+          "name": "CREATED_AT",
+          "settings": null,
+          "source": "breakout",
+          "fk_target_field_id": null,
+          "field_ref": [
+            "field",
+            41,
+            {
+              "base-type": "type/DateTime",
+              "temporal-unit": "month"
+            }
+          ],
+          "effective_type": "type/DateTime",
+          "nfc_path": null,
+          "parent_id": null,
+          "id": 41,
+          "position": 7,
+          "visibility_type": "normal",
+          "display_name": "Created At",
+          "fingerprint": {
+            "global": {
+              "distinct-count": 10001,
+              "nil%": 0.0
+            },
+            "type": {
+              "type/DateTime": {
+                "earliest": "2022-04-30T18:56:13.352Z",
+                "latest": "2026-04-19T14:07:15.657Z"
+              }
+            }
+          },
+          "base_type": "type/DateTime"
+        },
+        {
+          "base_type": "type/Integer",
+          "name": "count",
+          "display_name": "Count",
+          "semantic_type": "type/Quantity",
+          "source": "aggregation",
+          "field_ref": ["aggregation", 0],
+          "aggregation_index": 0
+        }
+      ],
+      "creator": {
+        "email": "anton@metabase.test",
+        "first_name": "Anton",
+        "last_login": "2024-09-24T15:34:26.000532+01:00",
+        "is_qbnewb": false,
+        "is_superuser": true,
+        "id": 1,
+        "last_name": "Kulyk",
+        "date_joined": "2024-08-19T15:09:37.030585+01:00",
+        "common_name": "Anton Kulyk"
+      },
+      "initially_published_at": null,
+      "can_write": true,
+      "database_id": 1,
+      "enable_embedding": false,
+      "collection_id": null,
+      "query_type": "query",
+      "name": "Bar chart with \"Other\"",
+      "last_query_start": "2024-10-03T14:40:03.849841+01:00",
+      "dashboard_count": 1,
+      "last_used_at": "2024-10-03T14:40:03.908296+01:00",
+      "type": "question",
+      "average_query_time": 71.93137254901961,
+      "creator_id": 1,
+      "can_restore": false,
+      "moderation_reviews": [],
+      "updated_at": "2024-10-04T14:53:50.393173+01:00",
+      "made_public_by_id": null,
+      "embedding_params": null,
+      "cache_ttl": null,
+      "dataset_query": {
+        "database": 1,
+        "type": "query",
+        "query": {
+          "source-table": 5,
+          "aggregation": [["count"]],
+          "breakout": [
+            [
+              "field",
+              48,
+              {
+                "base-type": "type/Text",
+                "source-field": 43
+              }
+            ],
+            [
+              "field",
+              41,
+              {
+                "base-type": "type/DateTime",
+                "temporal-unit": "month"
+              }
+            ]
+          ],
+          "filter": [
+            "and",
+            [
+              "between",
+              [
+                "field",
+                41,
+                {
+                  "base-type": "type/DateTime",
+                  "temporal-unit": "month"
+                }
+              ],
+              "2022-09-01T00:00Z",
+              "2023-02-01T00:00Z"
+            ],
+            [
+              "=",
+              [
+                "field",
+                48,
+                {
+                  "base-type": "type/Text",
+                  "source-field": 43
+                }
+              ],
+              "AK",
+              "AL",
+              "AR",
+              "AZ",
+              "CA",
+              "CO",
+              "CT",
+              "DE",
+              "FL",
+              "GA",
+              "IA",
+              "ID",
+              "IL",
+              "KY"
+            ]
+          ]
+        }
+      },
+      "id": 47,
+      "parameter_mappings": [],
+      "display": "bar",
+      "archived_directly": false,
+      "entity_id": "ez2Yb1JhGrltIJMNwZfwU",
+      "collection_preview": true,
+      "last-edit-info": {
+        "id": 1,
+        "email": "anton@metabase.test",
+        "first_name": "Anton",
+        "last_name": "Kulyk",
+        "timestamp": "2024-10-04T14:53:50.464787+01:00"
+      },
+      "visualization_settings": {
+        "graph.max_categories_enabled": true,
+        "graph.max_categories": 8,
+        "graph.dimensions": ["CREATED_AT", "STATE"],
+        "graph.series_order": [
+          {
+            "key": "AK",
+            "color": "#509EE3",
+            "enabled": true,
+            "name": "AK"
+          },
+          {
+            "key": "AL",
+            "color": "#227FD2",
+            "enabled": true,
+            "name": "AL"
+          },
+          {
+            "key": "AR",
+            "color": "#88BF4D",
+            "enabled": true,
+            "name": "AR"
+          },
+          {
+            "key": "AZ",
+            "color": "#689636",
+            "enabled": true,
+            "name": "AZ"
+          },
+          {
+            "key": "CA",
+            "color": "#A989C5",
+            "enabled": true,
+            "name": "CA"
+          },
+          {
+            "key": "CO",
+            "color": "#8A5EB0",
+            "enabled": true,
+            "name": "CO"
+          },
+          {
+            "key": "CT",
+            "color": "#EF8C8C",
+            "enabled": true,
+            "name": "CT"
+          },
+          {
+            "key": "DE",
+            "color": "#E75454",
+            "enabled": true,
+            "name": "DE"
+          },
+          {
+            "key": "GA",
+            "color": "#F9D45C",
+            "enabled": true,
+            "name": "GA"
+          },
+          {
+            "key": "IA",
+            "color": "#F7C41F",
+            "enabled": true,
+            "name": "IA"
+          },
+          {
+            "key": "ID",
+            "color": "#F2A86F",
+            "enabled": true,
+            "name": "ID"
+          },
+          {
+            "key": "KY",
+            "color": "#ED8535",
+            "enabled": true,
+            "name": "KY"
+          },
+          {
+            "key": "LA",
+            "color": "#98D9D9",
+            "enabled": true,
+            "name": "LA"
+          }
+        ],
+        "graph.series_order_dimension": "STATE",
+        "stackable.stack_type": null,
+        "pie.dimension": ["STATE"],
+        "graph.metrics": ["count"]
+      },
+      "collection": {
+        "metabase.models.collection.root/is-root?": true,
+        "authority_level": null,
+        "name": "Our analytics",
+        "is_personal": false,
+        "id": "root",
+        "can_write": true
+      },
+      "metabase_version": "v0.1.37-SNAPSHOT (5b4a5d6)",
+      "parameters": [],
+      "created_at": "2024-10-01T13:37:28.812936+01:00",
+      "parameter_usage_count": 0,
+      "public_uuid": null,
+      "can_delete": false
+    },
+    "data": {
+      "rows": [
+        ["AK", "2022-09-01T00:00:00+01:00", 2],
+        ["AK", "2022-10-01T00:00:00+01:00", 3],
+        ["AK", "2022-11-01T00:00:00Z", 1],
+        ["AK", "2022-12-01T00:00:00Z", 3],
+        ["AK", "2023-01-01T00:00:00Z", 9],
+        ["AK", "2023-02-01T00:00:00Z", 4],
+        ["AL", "2022-09-01T00:00:00+01:00", 1],
+        ["AL", "2022-10-01T00:00:00+01:00", 3],
+        ["AL", "2022-11-01T00:00:00Z", 2],
+        ["AL", "2022-12-01T00:00:00Z", 6],
+        ["AL", "2023-01-01T00:00:00Z", 6],
+        ["AL", "2023-02-01T00:00:00Z", 6],
+        ["AR", "2022-10-01T00:00:00+01:00", 2],
+        ["AR", "2022-11-01T00:00:00Z", 4],
+        ["AR", "2022-12-01T00:00:00Z", 3],
+        ["AR", "2023-01-01T00:00:00Z", 4],
+        ["AR", "2023-02-01T00:00:00Z", 1],
+        ["AZ", "2023-01-01T00:00:00Z", 1],
+        ["AZ", "2023-02-01T00:00:00Z", 1],
+        ["CA", "2022-09-01T00:00:00+01:00", 5],
+        ["CA", "2022-10-01T00:00:00+01:00", 5],
+        ["CA", "2022-11-01T00:00:00Z", 4],
+        ["CA", "2022-12-01T00:00:00Z", 6],
+        ["CA", "2023-01-01T00:00:00Z", 11],
+        ["CA", "2023-02-01T00:00:00Z", 11],
+        ["CO", "2022-09-01T00:00:00+01:00", 4],
+        ["CO", "2022-10-01T00:00:00+01:00", 6],
+        ["CO", "2022-11-01T00:00:00Z", 12],
+        ["CO", "2022-12-01T00:00:00Z", 8],
+        ["CO", "2023-01-01T00:00:00Z", 7],
+        ["CO", "2023-02-01T00:00:00Z", 9],
+        ["CT", "2022-10-01T00:00:00+01:00", 1],
+        ["DE", "2022-10-01T00:00:00+01:00", 1],
+        ["DE", "2022-12-01T00:00:00Z", 1],
+        ["FL", "2022-09-01T00:00:00+01:00", 1],
+        ["FL", "2022-10-01T00:00:00+01:00", 2],
+        ["FL", "2022-11-01T00:00:00Z", 4],
+        ["FL", "2023-01-01T00:00:00Z", 3],
+        ["FL", "2023-02-01T00:00:00Z", 4],
+        ["GA", "2022-09-01T00:00:00+01:00", 1],
+        ["GA", "2022-10-01T00:00:00+01:00", 7],
+        ["GA", "2022-11-01T00:00:00Z", 3],
+        ["GA", "2022-12-01T00:00:00Z", 1],
+        ["GA", "2023-01-01T00:00:00Z", 8],
+        ["GA", "2023-02-01T00:00:00Z", 3],
+        ["IA", "2022-09-01T00:00:00+01:00", 3],
+        ["IA", "2022-10-01T00:00:00+01:00", 4],
+        ["IA", "2022-11-01T00:00:00Z", 5],
+        ["IA", "2022-12-01T00:00:00Z", 5],
+        ["IA", "2023-01-01T00:00:00Z", 10],
+        ["IA", "2023-02-01T00:00:00Z", 7],
+        ["ID", "2022-09-01T00:00:00+01:00", 1],
+        ["ID", "2022-10-01T00:00:00+01:00", 1],
+        ["ID", "2022-11-01T00:00:00Z", 1],
+        ["ID", "2022-12-01T00:00:00Z", 2],
+        ["ID", "2023-01-01T00:00:00Z", 3],
+        ["ID", "2023-02-01T00:00:00Z", 4],
+        ["IL", "2022-09-01T00:00:00+01:00", 1],
+        ["IL", "2022-10-01T00:00:00+01:00", 3],
+        ["IL", "2022-11-01T00:00:00Z", 3],
+        ["IL", "2022-12-01T00:00:00Z", 6],
+        ["IL", "2023-01-01T00:00:00Z", 5],
+        ["IL", "2023-02-01T00:00:00Z", 5],
+        ["KY", "2022-09-01T00:00:00+01:00", 2],
+        ["KY", "2022-10-01T00:00:00+01:00", 5],
+        ["KY", "2022-11-01T00:00:00Z", 5],
+        ["KY", "2022-12-01T00:00:00Z", 4],
+        ["KY", "2023-01-01T00:00:00Z", 4],
+        ["KY", "2023-02-01T00:00:00Z", 3]
+      ],
+      "cols": [
+        {
+          "description": "The state or province of the account’s billing address",
+          "database_type": "CHARACTER",
+          "semantic_type": "type/State",
+          "table_id": 3,
+          "coercion_strategy": null,
+          "name": "STATE",
+          "settings": null,
+          "source": "breakout",
+          "fk_target_field_id": null,
+          "fk_field_id": 43,
+          "field_ref": [
+            "field",
+            48,
+            {
+              "base-type": "type/Text",
+              "source-field": 43
+            }
+          ],
+          "effective_type": "type/Text",
+          "nfc_path": null,
+          "parent_id": null,
+          "id": 48,
+          "position": 7,
+          "visibility_type": "normal",
+          "display_name": "User → State",
+          "fingerprint": {
+            "global": {
+              "distinct-count": 49,
+              "nil%": 0.0
+            },
+            "type": {
+              "type/Text": {
+                "percent-json": 0.0,
+                "percent-url": 0.0,
+                "percent-email": 0.0,
+                "percent-state": 1.0,
+                "average-length": 2.0
+              }
+            }
+          },
+          "base_type": "type/Text",
+          "source_alias": "PEOPLE__via__USER_ID"
+        },
+        {
+          "description": "The date and time an order was submitted.",
+          "database_type": "TIMESTAMP",
+          "semantic_type": "type/CreationTimestamp",
+          "table_id": 5,
+          "coercion_strategy": null,
+          "unit": "month",
+          "name": "CREATED_AT",
+          "settings": null,
+          "source": "breakout",
+          "fk_target_field_id": null,
+          "field_ref": [
+            "field",
+            41,
+            {
+              "base-type": "type/DateTime",
+              "temporal-unit": "month"
+            }
+          ],
+          "effective_type": "type/DateTime",
+          "nfc_path": null,
+          "parent_id": null,
+          "id": 41,
+          "position": 7,
+          "visibility_type": "normal",
+          "display_name": "Created At",
+          "fingerprint": {
+            "global": {
+              "distinct-count": 10001,
+              "nil%": 0.0
+            },
+            "type": {
+              "type/DateTime": {
+                "earliest": "2022-04-30T18:56:13.352Z",
+                "latest": "2026-04-19T14:07:15.657Z"
+              }
+            }
+          },
+          "base_type": "type/DateTime"
+        },
+        {
+          "database_type": "BIGINT",
+          "semantic_type": "type/Quantity",
+          "name": "count",
+          "source": "aggregation",
+          "field_ref": ["aggregation", 0],
+          "effective_type": "type/BigInteger",
+          "aggregation_index": 0,
+          "display_name": "Count",
+          "base_type": "type/BigInteger"
+        }
+      ],
+      "native_form": {
+        "query": "SELECT \"PEOPLE__via__USER_ID\".\"STATE\" AS \"PEOPLE__via__USER_ID__STATE\", DATE_TRUNC('month', \"PUBLIC\".\"ORDERS\".\"CREATED_AT\") AS \"CREATED_AT\", COUNT(*) AS \"count\" FROM \"PUBLIC\".\"ORDERS\" LEFT JOIN \"PUBLIC\".\"PEOPLE\" AS \"PEOPLE__via__USER_ID\" ON \"PUBLIC\".\"ORDERS\".\"USER_ID\" = \"PEOPLE__via__USER_ID\".\"ID\" WHERE (\"PUBLIC\".\"ORDERS\".\"CREATED_AT\" >= timestamp '2022-09-01 00:00:00.000') AND (\"PUBLIC\".\"ORDERS\".\"CREATED_AT\" < timestamp '2023-03-01 00:00:00.000') AND ((\"PEOPLE__via__USER_ID\".\"STATE\" = 'AK') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'AL') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'AR') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'AZ') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'CA') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'CO') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'CT') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'DE') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'FL') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'GA') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'IA') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'ID') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'IL') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'KY')) GROUP BY \"PEOPLE__via__USER_ID\".\"STATE\", DATE_TRUNC('month', \"PUBLIC\".\"ORDERS\".\"CREATED_AT\") ORDER BY \"PEOPLE__via__USER_ID\".\"STATE\" ASC, DATE_TRUNC('month', \"PUBLIC\".\"ORDERS\".\"CREATED_AT\") ASC",
+        "params": null
+      },
+      "format-rows?": true,
+      "results_timezone": "Europe/Lisbon",
+      "results_metadata": {
+        "columns": [
+          {
+            "description": "The state or province of the account’s billing address",
+            "semantic_type": "type/State",
+            "coercion_strategy": null,
+            "name": "STATE",
+            "settings": null,
+            "fk_target_field_id": null,
+            "field_ref": [
+              "field",
+              48,
+              {
+                "base-type": "type/Text",
+                "source-field": 43
+              }
+            ],
+            "effective_type": "type/Text",
+            "id": 48,
+            "visibility_type": "normal",
+            "display_name": "User → State",
+            "fingerprint": {
+              "global": {
+                "distinct-count": 49,
+                "nil%": 0.0
+              },
+              "type": {
+                "type/Text": {
+                  "percent-json": 0.0,
+                  "percent-url": 0.0,
+                  "percent-email": 0.0,
+                  "percent-state": 1.0,
+                  "average-length": 2.0
+                }
+              }
+            },
+            "base_type": "type/Text"
+          },
+          {
+            "description": "The date and time an order was submitted.",
+            "semantic_type": "type/CreationTimestamp",
+            "coercion_strategy": null,
+            "unit": "month",
+            "name": "CREATED_AT",
+            "settings": null,
+            "fk_target_field_id": null,
+            "field_ref": [
+              "field",
+              41,
+              {
+                "base-type": "type/DateTime",
+                "temporal-unit": "month"
+              }
+            ],
+            "effective_type": "type/DateTime",
+            "id": 41,
+            "visibility_type": "normal",
+            "display_name": "Created At",
+            "fingerprint": {
+              "global": {
+                "distinct-count": 10001,
+                "nil%": 0.0
+              },
+              "type": {
+                "type/DateTime": {
+                  "earliest": "2022-04-30T18:56:13.352Z",
+                  "latest": "2026-04-19T14:07:15.657Z"
+                }
+              }
+            },
+            "base_type": "type/DateTime"
+          },
+          {
+            "display_name": "Count",
+            "semantic_type": "type/Quantity",
+            "field_ref": ["aggregation", 0],
+            "base_type": "type/BigInteger",
+            "effective_type": "type/BigInteger",
+            "name": "count",
+            "fingerprint": {
+              "global": {
+                "distinct-count": 12,
+                "nil%": 0.0
+              },
+              "type": {
+                "type/Number": {
+                  "min": 1.0,
+                  "q1": 1.8849307066960952,
+                  "q3": 5.5,
+                  "max": 12.0,
+                  "sd": 2.737211604119948,
+                  "avg": 4.086956521739131
+                }
+              }
+            }
+          }
+        ]
+      },
+      "insights": [
+        {
+          "previous-value": 4,
+          "unit": "month",
+          "offset": -377.8969468095498,
+          "last-change": -0.25,
+          "col": "count",
+          "slope": 0.019777876708186145,
+          "last-value": 3,
+          "best-fit": [
+            "*",
+            4.201731368215701e-45,
+            ["exp", ["*", 0.005350764152580669, "x"]]
+          ]
+        }
+      ]
+    }
+  }
+]
diff --git a/frontend/src/metabase/static-viz/components/ComboChart/stories-data/bar-max-categories-stacked-normalized.json b/frontend/src/metabase/static-viz/components/ComboChart/stories-data/bar-max-categories-stacked-normalized.json
new file mode 100644
index 00000000000..5c9bd15df42
--- /dev/null
+++ b/frontend/src/metabase/static-viz/components/ComboChart/stories-data/bar-max-categories-stacked-normalized.json
@@ -0,0 +1,606 @@
+[
+  {
+    "card": {
+      "cache_invalidated_at": null,
+      "description": null,
+      "archived": false,
+      "view_count": 151,
+      "collection_position": null,
+      "source_card_id": null,
+      "table_id": 5,
+      "can_run_adhoc_query": true,
+      "result_metadata": [
+        {
+          "description": "The state or province of the account’s billing address",
+          "semantic_type": "type/State",
+          "coercion_strategy": null,
+          "name": "STATE",
+          "settings": null,
+          "fk_target_field_id": null,
+          "field_ref": [
+            "field",
+            48,
+            {
+              "base-type": "type/Text",
+              "source-field": 43
+            }
+          ],
+          "effective_type": "type/Text",
+          "id": 48,
+          "visibility_type": "normal",
+          "display_name": "User → State",
+          "fingerprint": {
+            "global": {
+              "distinct-count": 49,
+              "nil%": 0
+            },
+            "type": {
+              "type/Text": {
+                "percent-json": 0,
+                "percent-url": 0,
+                "percent-email": 0,
+                "percent-state": 1,
+                "average-length": 2
+              }
+            }
+          },
+          "base_type": "type/Text"
+        },
+        {
+          "description": "The date and time an order was submitted.",
+          "semantic_type": "type/CreationTimestamp",
+          "coercion_strategy": null,
+          "unit": "month",
+          "name": "CREATED_AT",
+          "settings": null,
+          "fk_target_field_id": null,
+          "field_ref": [
+            "field",
+            41,
+            {
+              "base-type": "type/DateTime",
+              "temporal-unit": "month"
+            }
+          ],
+          "effective_type": "type/DateTime",
+          "id": 41,
+          "visibility_type": "normal",
+          "display_name": "Created At",
+          "fingerprint": {
+            "global": {
+              "distinct-count": 10001,
+              "nil%": 0
+            },
+            "type": {
+              "type/DateTime": {
+                "earliest": "2022-04-30T18:56:13.352Z",
+                "latest": "2026-04-19T14:07:15.657Z"
+              }
+            }
+          },
+          "base_type": "type/DateTime"
+        },
+        {
+          "display_name": "Count",
+          "semantic_type": "type/Quantity",
+          "field_ref": ["aggregation", 0],
+          "base_type": "type/BigInteger",
+          "effective_type": "type/BigInteger",
+          "name": "count",
+          "fingerprint": {
+            "global": {
+              "distinct-count": 12,
+              "nil%": 0
+            },
+            "type": {
+              "type/Number": {
+                "min": 1,
+                "q1": 1.8849307066960952,
+                "q3": 5.5,
+                "max": 12,
+                "sd": 2.737211604119948,
+                "avg": 4.086956521739131
+              }
+            }
+          }
+        }
+      ],
+      "creator": {
+        "email": "anton@metabase.test",
+        "first_name": "Anton",
+        "last_login": "2024-09-24T15:34:26.000532+01:00",
+        "is_qbnewb": false,
+        "is_superuser": true,
+        "id": 1,
+        "last_name": "Kulyk",
+        "date_joined": "2024-08-19T15:09:37.030585+01:00",
+        "common_name": "Anton Kulyk"
+      },
+      "initially_published_at": null,
+      "can_write": true,
+      "database_id": 1,
+      "enable_embedding": false,
+      "collection_id": null,
+      "query_type": "query",
+      "name": "Bar chart with \"Other\"",
+      "last_query_start": "2024-10-04T14:53:58.731799+01:00",
+      "dashboard_count": 1,
+      "last_used_at": "2024-10-04T14:53:58.783195+01:00",
+      "type": "question",
+      "average_query_time": 71.96116504854369,
+      "creator_id": 1,
+      "can_restore": false,
+      "moderation_reviews": [],
+      "updated_at": "2024-10-04T15:00:55.349248+01:00",
+      "made_public_by_id": null,
+      "embedding_params": null,
+      "cache_ttl": null,
+      "dataset_query": {
+        "database": 1,
+        "type": "query",
+        "query": {
+          "source-table": 5,
+          "aggregation": [["count"]],
+          "breakout": [
+            [
+              "field",
+              48,
+              {
+                "base-type": "type/Text",
+                "source-field": 43
+              }
+            ],
+            [
+              "field",
+              41,
+              {
+                "base-type": "type/DateTime",
+                "temporal-unit": "month"
+              }
+            ]
+          ],
+          "filter": [
+            "and",
+            [
+              "between",
+              [
+                "field",
+                41,
+                {
+                  "base-type": "type/DateTime",
+                  "temporal-unit": "month"
+                }
+              ],
+              "2022-09-01T00:00Z",
+              "2023-02-01T00:00Z"
+            ],
+            [
+              "=",
+              [
+                "field",
+                48,
+                {
+                  "base-type": "type/Text",
+                  "source-field": 43
+                }
+              ],
+              "AK",
+              "AL",
+              "AR",
+              "AZ",
+              "CA",
+              "CO",
+              "CT",
+              "DE",
+              "FL",
+              "GA",
+              "IA",
+              "ID",
+              "IL",
+              "KY"
+            ]
+          ]
+        }
+      },
+      "id": 47,
+      "parameter_mappings": [],
+      "display": "bar",
+      "archived_directly": false,
+      "entity_id": "ez2Yb1JhGrltIJMNwZfwU",
+      "collection_preview": true,
+      "last-edit-info": {
+        "timestamp": "2024-10-04T14:00:55.394Z",
+        "id": 1,
+        "first_name": "Anton",
+        "last_name": "Kulyk",
+        "email": "anton@metabase.test"
+      },
+      "visualization_settings": {
+        "graph.max_categories_enabled": true,
+        "graph.max_categories": 10,
+        "graph.dimensions": ["CREATED_AT", "STATE"],
+        "graph.series_order": [
+          {
+            "key": "AK",
+            "color": "#509EE3",
+            "enabled": true,
+            "name": "AK"
+          },
+          {
+            "key": "AL",
+            "color": "#227FD2",
+            "enabled": true,
+            "name": "AL"
+          },
+          {
+            "key": "AR",
+            "color": "#88BF4D",
+            "enabled": true,
+            "name": "AR"
+          },
+          {
+            "key": "AZ",
+            "color": "#689636",
+            "enabled": true,
+            "name": "AZ"
+          },
+          {
+            "key": "CA",
+            "color": "#A989C5",
+            "enabled": true,
+            "name": "CA"
+          },
+          {
+            "key": "CO",
+            "color": "#8A5EB0",
+            "enabled": true,
+            "name": "CO"
+          },
+          {
+            "key": "CT",
+            "color": "#EF8C8C",
+            "enabled": true,
+            "name": "CT"
+          },
+          {
+            "key": "DE",
+            "color": "#E75454",
+            "enabled": true,
+            "name": "DE"
+          },
+          {
+            "key": "GA",
+            "color": "#F9D45C",
+            "enabled": true,
+            "name": "GA"
+          },
+          {
+            "key": "IA",
+            "color": "#F7C41F",
+            "enabled": true,
+            "name": "IA"
+          },
+          {
+            "key": "ID",
+            "color": "#F2A86F",
+            "enabled": true,
+            "name": "ID"
+          },
+          {
+            "key": "KY",
+            "color": "#ED8535",
+            "enabled": true,
+            "name": "KY"
+          },
+          {
+            "key": "LA",
+            "color": "#98D9D9",
+            "enabled": true,
+            "name": "LA"
+          }
+        ],
+        "graph.series_order_dimension": "STATE",
+        "stackable.stack_type": "normalized",
+        "pie.dimension": ["STATE"],
+        "graph.metrics": ["count"]
+      },
+      "collection": null,
+      "metabase_version": "v0.1.37-SNAPSHOT (5b4a5d6)",
+      "parameters": [],
+      "created_at": "2024-10-01T13:37:28.812936+01:00",
+      "parameter_usage_count": 0,
+      "public_uuid": null,
+      "can_delete": false
+    },
+    "data": {
+      "rows": [
+        ["AK", "2022-09-01T00:00:00+01:00", 2],
+        ["AK", "2022-10-01T00:00:00+01:00", 3],
+        ["AK", "2022-11-01T00:00:00Z", 1],
+        ["AK", "2022-12-01T00:00:00Z", 3],
+        ["AK", "2023-01-01T00:00:00Z", 9],
+        ["AK", "2023-02-01T00:00:00Z", 4],
+        ["AL", "2022-09-01T00:00:00+01:00", 1],
+        ["AL", "2022-10-01T00:00:00+01:00", 3],
+        ["AL", "2022-11-01T00:00:00Z", 2],
+        ["AL", "2022-12-01T00:00:00Z", 6],
+        ["AL", "2023-01-01T00:00:00Z", 6],
+        ["AL", "2023-02-01T00:00:00Z", 6],
+        ["AR", "2022-10-01T00:00:00+01:00", 2],
+        ["AR", "2022-11-01T00:00:00Z", 4],
+        ["AR", "2022-12-01T00:00:00Z", 3],
+        ["AR", "2023-01-01T00:00:00Z", 4],
+        ["AR", "2023-02-01T00:00:00Z", 1],
+        ["AZ", "2023-01-01T00:00:00Z", 1],
+        ["AZ", "2023-02-01T00:00:00Z", 1],
+        ["CA", "2022-09-01T00:00:00+01:00", 5],
+        ["CA", "2022-10-01T00:00:00+01:00", 5],
+        ["CA", "2022-11-01T00:00:00Z", 4],
+        ["CA", "2022-12-01T00:00:00Z", 6],
+        ["CA", "2023-01-01T00:00:00Z", 11],
+        ["CA", "2023-02-01T00:00:00Z", 11],
+        ["CO", "2022-09-01T00:00:00+01:00", 4],
+        ["CO", "2022-10-01T00:00:00+01:00", 6],
+        ["CO", "2022-11-01T00:00:00Z", 12],
+        ["CO", "2022-12-01T00:00:00Z", 8],
+        ["CO", "2023-01-01T00:00:00Z", 7],
+        ["CO", "2023-02-01T00:00:00Z", 9],
+        ["CT", "2022-10-01T00:00:00+01:00", 1],
+        ["DE", "2022-10-01T00:00:00+01:00", 1],
+        ["DE", "2022-12-01T00:00:00Z", 1],
+        ["FL", "2022-09-01T00:00:00+01:00", 1],
+        ["FL", "2022-10-01T00:00:00+01:00", 2],
+        ["FL", "2022-11-01T00:00:00Z", 4],
+        ["FL", "2023-01-01T00:00:00Z", 3],
+        ["FL", "2023-02-01T00:00:00Z", 4],
+        ["GA", "2022-09-01T00:00:00+01:00", 1],
+        ["GA", "2022-10-01T00:00:00+01:00", 7],
+        ["GA", "2022-11-01T00:00:00Z", 3],
+        ["GA", "2022-12-01T00:00:00Z", 1],
+        ["GA", "2023-01-01T00:00:00Z", 8],
+        ["GA", "2023-02-01T00:00:00Z", 3],
+        ["IA", "2022-09-01T00:00:00+01:00", 3],
+        ["IA", "2022-10-01T00:00:00+01:00", 4],
+        ["IA", "2022-11-01T00:00:00Z", 5],
+        ["IA", "2022-12-01T00:00:00Z", 5],
+        ["IA", "2023-01-01T00:00:00Z", 10],
+        ["IA", "2023-02-01T00:00:00Z", 7],
+        ["ID", "2022-09-01T00:00:00+01:00", 1],
+        ["ID", "2022-10-01T00:00:00+01:00", 1],
+        ["ID", "2022-11-01T00:00:00Z", 1],
+        ["ID", "2022-12-01T00:00:00Z", 2],
+        ["ID", "2023-01-01T00:00:00Z", 3],
+        ["ID", "2023-02-01T00:00:00Z", 4],
+        ["IL", "2022-09-01T00:00:00+01:00", 1],
+        ["IL", "2022-10-01T00:00:00+01:00", 3],
+        ["IL", "2022-11-01T00:00:00Z", 3],
+        ["IL", "2022-12-01T00:00:00Z", 6],
+        ["IL", "2023-01-01T00:00:00Z", 5],
+        ["IL", "2023-02-01T00:00:00Z", 5],
+        ["KY", "2022-09-01T00:00:00+01:00", 2],
+        ["KY", "2022-10-01T00:00:00+01:00", 5],
+        ["KY", "2022-11-01T00:00:00Z", 5],
+        ["KY", "2022-12-01T00:00:00Z", 4],
+        ["KY", "2023-01-01T00:00:00Z", 4],
+        ["KY", "2023-02-01T00:00:00Z", 3]
+      ],
+      "cols": [
+        {
+          "description": "The state or province of the account’s billing address",
+          "database_type": "CHARACTER",
+          "semantic_type": "type/State",
+          "table_id": 3,
+          "coercion_strategy": null,
+          "name": "STATE",
+          "settings": null,
+          "source": "breakout",
+          "fk_target_field_id": null,
+          "fk_field_id": 43,
+          "field_ref": [
+            "field",
+            48,
+            {
+              "base-type": "type/Text",
+              "source-field": 43
+            }
+          ],
+          "effective_type": "type/Text",
+          "nfc_path": null,
+          "parent_id": null,
+          "id": 48,
+          "position": 7,
+          "visibility_type": "normal",
+          "display_name": "User → State",
+          "fingerprint": {
+            "global": {
+              "distinct-count": 49,
+              "nil%": 0.0
+            },
+            "type": {
+              "type/Text": {
+                "percent-json": 0.0,
+                "percent-url": 0.0,
+                "percent-email": 0.0,
+                "percent-state": 1.0,
+                "average-length": 2.0
+              }
+            }
+          },
+          "base_type": "type/Text",
+          "source_alias": "PEOPLE__via__USER_ID"
+        },
+        {
+          "description": "The date and time an order was submitted.",
+          "database_type": "TIMESTAMP",
+          "semantic_type": "type/CreationTimestamp",
+          "table_id": 5,
+          "coercion_strategy": null,
+          "unit": "month",
+          "name": "CREATED_AT",
+          "settings": null,
+          "source": "breakout",
+          "fk_target_field_id": null,
+          "field_ref": [
+            "field",
+            41,
+            {
+              "base-type": "type/DateTime",
+              "temporal-unit": "month"
+            }
+          ],
+          "effective_type": "type/DateTime",
+          "nfc_path": null,
+          "parent_id": null,
+          "id": 41,
+          "position": 7,
+          "visibility_type": "normal",
+          "display_name": "Created At",
+          "fingerprint": {
+            "global": {
+              "distinct-count": 10001,
+              "nil%": 0.0
+            },
+            "type": {
+              "type/DateTime": {
+                "earliest": "2022-04-30T18:56:13.352Z",
+                "latest": "2026-04-19T14:07:15.657Z"
+              }
+            }
+          },
+          "base_type": "type/DateTime"
+        },
+        {
+          "database_type": "BIGINT",
+          "semantic_type": "type/Quantity",
+          "name": "count",
+          "source": "aggregation",
+          "field_ref": ["aggregation", 0],
+          "effective_type": "type/BigInteger",
+          "aggregation_index": 0,
+          "display_name": "Count",
+          "base_type": "type/BigInteger"
+        }
+      ],
+      "native_form": {
+        "query": "SELECT \"PEOPLE__via__USER_ID\".\"STATE\" AS \"PEOPLE__via__USER_ID__STATE\", DATE_TRUNC('month', \"PUBLIC\".\"ORDERS\".\"CREATED_AT\") AS \"CREATED_AT\", COUNT(*) AS \"count\" FROM \"PUBLIC\".\"ORDERS\" LEFT JOIN \"PUBLIC\".\"PEOPLE\" AS \"PEOPLE__via__USER_ID\" ON \"PUBLIC\".\"ORDERS\".\"USER_ID\" = \"PEOPLE__via__USER_ID\".\"ID\" WHERE (\"PUBLIC\".\"ORDERS\".\"CREATED_AT\" >= timestamp '2022-09-01 00:00:00.000') AND (\"PUBLIC\".\"ORDERS\".\"CREATED_AT\" < timestamp '2023-03-01 00:00:00.000') AND ((\"PEOPLE__via__USER_ID\".\"STATE\" = 'AK') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'AL') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'AR') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'AZ') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'CA') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'CO') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'CT') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'DE') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'FL') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'GA') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'IA') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'ID') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'IL') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'KY')) GROUP BY \"PEOPLE__via__USER_ID\".\"STATE\", DATE_TRUNC('month', \"PUBLIC\".\"ORDERS\".\"CREATED_AT\") ORDER BY \"PEOPLE__via__USER_ID\".\"STATE\" ASC, DATE_TRUNC('month', \"PUBLIC\".\"ORDERS\".\"CREATED_AT\") ASC",
+        "params": null
+      },
+      "format-rows?": true,
+      "results_timezone": "Europe/Lisbon",
+      "results_metadata": {
+        "columns": [
+          {
+            "description": "The state or province of the account’s billing address",
+            "semantic_type": "type/State",
+            "coercion_strategy": null,
+            "name": "STATE",
+            "settings": null,
+            "fk_target_field_id": null,
+            "field_ref": [
+              "field",
+              48,
+              {
+                "base-type": "type/Text",
+                "source-field": 43
+              }
+            ],
+            "effective_type": "type/Text",
+            "id": 48,
+            "visibility_type": "normal",
+            "display_name": "User → State",
+            "fingerprint": {
+              "global": {
+                "distinct-count": 49,
+                "nil%": 0.0
+              },
+              "type": {
+                "type/Text": {
+                  "percent-json": 0.0,
+                  "percent-url": 0.0,
+                  "percent-email": 0.0,
+                  "percent-state": 1.0,
+                  "average-length": 2.0
+                }
+              }
+            },
+            "base_type": "type/Text"
+          },
+          {
+            "description": "The date and time an order was submitted.",
+            "semantic_type": "type/CreationTimestamp",
+            "coercion_strategy": null,
+            "unit": "month",
+            "name": "CREATED_AT",
+            "settings": null,
+            "fk_target_field_id": null,
+            "field_ref": [
+              "field",
+              41,
+              {
+                "base-type": "type/DateTime",
+                "temporal-unit": "month"
+              }
+            ],
+            "effective_type": "type/DateTime",
+            "id": 41,
+            "visibility_type": "normal",
+            "display_name": "Created At",
+            "fingerprint": {
+              "global": {
+                "distinct-count": 10001,
+                "nil%": 0.0
+              },
+              "type": {
+                "type/DateTime": {
+                  "earliest": "2022-04-30T18:56:13.352Z",
+                  "latest": "2026-04-19T14:07:15.657Z"
+                }
+              }
+            },
+            "base_type": "type/DateTime"
+          },
+          {
+            "display_name": "Count",
+            "semantic_type": "type/Quantity",
+            "field_ref": ["aggregation", 0],
+            "base_type": "type/BigInteger",
+            "effective_type": "type/BigInteger",
+            "name": "count",
+            "fingerprint": {
+              "global": {
+                "distinct-count": 12,
+                "nil%": 0.0
+              },
+              "type": {
+                "type/Number": {
+                  "min": 1.0,
+                  "q1": 1.8849307066960952,
+                  "q3": 5.5,
+                  "max": 12.0,
+                  "sd": 2.737211604119948,
+                  "avg": 4.086956521739131
+                }
+              }
+            }
+          }
+        ]
+      },
+      "insights": [
+        {
+          "previous-value": 4,
+          "unit": "month",
+          "offset": -377.8969468095498,
+          "last-change": -0.25,
+          "col": "count",
+          "slope": 0.019777876708186145,
+          "last-value": 3,
+          "best-fit": [
+            "*",
+            4.201731368215701e-45,
+            ["exp", ["*", 0.005350764152580669, "x"]]
+          ]
+        }
+      ]
+    }
+  }
+]
diff --git a/frontend/src/metabase/static-viz/components/ComboChart/stories-data/bar-max-categories-stacked.json b/frontend/src/metabase/static-viz/components/ComboChart/stories-data/bar-max-categories-stacked.json
new file mode 100644
index 00000000000..1dd35791d49
--- /dev/null
+++ b/frontend/src/metabase/static-viz/components/ComboChart/stories-data/bar-max-categories-stacked.json
@@ -0,0 +1,606 @@
+[
+  {
+    "card": {
+      "cache_invalidated_at": null,
+      "description": null,
+      "archived": false,
+      "view_count": 151,
+      "collection_position": null,
+      "source_card_id": null,
+      "table_id": 5,
+      "can_run_adhoc_query": true,
+      "result_metadata": [
+        {
+          "description": "The state or province of the account’s billing address",
+          "semantic_type": "type/State",
+          "coercion_strategy": null,
+          "name": "STATE",
+          "settings": null,
+          "fk_target_field_id": null,
+          "field_ref": [
+            "field",
+            48,
+            {
+              "base-type": "type/Text",
+              "source-field": 43
+            }
+          ],
+          "effective_type": "type/Text",
+          "id": 48,
+          "visibility_type": "normal",
+          "display_name": "User → State",
+          "fingerprint": {
+            "global": {
+              "distinct-count": 49,
+              "nil%": 0
+            },
+            "type": {
+              "type/Text": {
+                "percent-json": 0,
+                "percent-url": 0,
+                "percent-email": 0,
+                "percent-state": 1,
+                "average-length": 2
+              }
+            }
+          },
+          "base_type": "type/Text"
+        },
+        {
+          "description": "The date and time an order was submitted.",
+          "semantic_type": "type/CreationTimestamp",
+          "coercion_strategy": null,
+          "unit": "month",
+          "name": "CREATED_AT",
+          "settings": null,
+          "fk_target_field_id": null,
+          "field_ref": [
+            "field",
+            41,
+            {
+              "base-type": "type/DateTime",
+              "temporal-unit": "month"
+            }
+          ],
+          "effective_type": "type/DateTime",
+          "id": 41,
+          "visibility_type": "normal",
+          "display_name": "Created At",
+          "fingerprint": {
+            "global": {
+              "distinct-count": 10001,
+              "nil%": 0
+            },
+            "type": {
+              "type/DateTime": {
+                "earliest": "2022-04-30T18:56:13.352Z",
+                "latest": "2026-04-19T14:07:15.657Z"
+              }
+            }
+          },
+          "base_type": "type/DateTime"
+        },
+        {
+          "display_name": "Count",
+          "semantic_type": "type/Quantity",
+          "field_ref": ["aggregation", 0],
+          "base_type": "type/BigInteger",
+          "effective_type": "type/BigInteger",
+          "name": "count",
+          "fingerprint": {
+            "global": {
+              "distinct-count": 12,
+              "nil%": 0
+            },
+            "type": {
+              "type/Number": {
+                "min": 1,
+                "q1": 1.8849307066960952,
+                "q3": 5.5,
+                "max": 12,
+                "sd": 2.737211604119948,
+                "avg": 4.086956521739131
+              }
+            }
+          }
+        }
+      ],
+      "creator": {
+        "email": "anton@metabase.test",
+        "first_name": "Anton",
+        "last_login": "2024-09-24T15:34:26.000532+01:00",
+        "is_qbnewb": false,
+        "is_superuser": true,
+        "id": 1,
+        "last_name": "Kulyk",
+        "date_joined": "2024-08-19T15:09:37.030585+01:00",
+        "common_name": "Anton Kulyk"
+      },
+      "initially_published_at": null,
+      "can_write": true,
+      "database_id": 1,
+      "enable_embedding": false,
+      "collection_id": null,
+      "query_type": "query",
+      "name": "Bar chart with \"Other\"",
+      "last_query_start": "2024-10-04T14:53:58.731799+01:00",
+      "dashboard_count": 1,
+      "last_used_at": "2024-10-04T14:53:58.783195+01:00",
+      "type": "question",
+      "average_query_time": 71.96116504854369,
+      "creator_id": 1,
+      "can_restore": false,
+      "moderation_reviews": [],
+      "updated_at": "2024-10-04T14:58:53.488082+01:00",
+      "made_public_by_id": null,
+      "embedding_params": null,
+      "cache_ttl": null,
+      "dataset_query": {
+        "database": 1,
+        "type": "query",
+        "query": {
+          "source-table": 5,
+          "aggregation": [["count"]],
+          "breakout": [
+            [
+              "field",
+              48,
+              {
+                "base-type": "type/Text",
+                "source-field": 43
+              }
+            ],
+            [
+              "field",
+              41,
+              {
+                "base-type": "type/DateTime",
+                "temporal-unit": "month"
+              }
+            ]
+          ],
+          "filter": [
+            "and",
+            [
+              "between",
+              [
+                "field",
+                41,
+                {
+                  "base-type": "type/DateTime",
+                  "temporal-unit": "month"
+                }
+              ],
+              "2022-09-01T00:00Z",
+              "2023-02-01T00:00Z"
+            ],
+            [
+              "=",
+              [
+                "field",
+                48,
+                {
+                  "base-type": "type/Text",
+                  "source-field": 43
+                }
+              ],
+              "AK",
+              "AL",
+              "AR",
+              "AZ",
+              "CA",
+              "CO",
+              "CT",
+              "DE",
+              "FL",
+              "GA",
+              "IA",
+              "ID",
+              "IL",
+              "KY"
+            ]
+          ]
+        }
+      },
+      "id": 47,
+      "parameter_mappings": [],
+      "display": "bar",
+      "archived_directly": false,
+      "entity_id": "ez2Yb1JhGrltIJMNwZfwU",
+      "collection_preview": true,
+      "last-edit-info": {
+        "timestamp": "2024-10-04T13:58:53.546Z",
+        "id": 1,
+        "first_name": "Anton",
+        "last_name": "Kulyk",
+        "email": "anton@metabase.test"
+      },
+      "visualization_settings": {
+        "graph.max_categories_enabled": true,
+        "graph.max_categories": 4,
+        "graph.dimensions": ["CREATED_AT", "STATE"],
+        "graph.series_order": [
+          {
+            "key": "AK",
+            "color": "#509EE3",
+            "enabled": true,
+            "name": "AK"
+          },
+          {
+            "key": "AL",
+            "color": "#227FD2",
+            "enabled": true,
+            "name": "AL"
+          },
+          {
+            "key": "AR",
+            "color": "#88BF4D",
+            "enabled": true,
+            "name": "AR"
+          },
+          {
+            "key": "AZ",
+            "color": "#689636",
+            "enabled": true,
+            "name": "AZ"
+          },
+          {
+            "key": "CA",
+            "color": "#A989C5",
+            "enabled": true,
+            "name": "CA"
+          },
+          {
+            "key": "CO",
+            "color": "#8A5EB0",
+            "enabled": true,
+            "name": "CO"
+          },
+          {
+            "key": "CT",
+            "color": "#EF8C8C",
+            "enabled": true,
+            "name": "CT"
+          },
+          {
+            "key": "DE",
+            "color": "#E75454",
+            "enabled": true,
+            "name": "DE"
+          },
+          {
+            "key": "GA",
+            "color": "#F9D45C",
+            "enabled": true,
+            "name": "GA"
+          },
+          {
+            "key": "IA",
+            "color": "#F7C41F",
+            "enabled": true,
+            "name": "IA"
+          },
+          {
+            "key": "ID",
+            "color": "#F2A86F",
+            "enabled": true,
+            "name": "ID"
+          },
+          {
+            "key": "KY",
+            "color": "#ED8535",
+            "enabled": true,
+            "name": "KY"
+          },
+          {
+            "key": "LA",
+            "color": "#98D9D9",
+            "enabled": true,
+            "name": "LA"
+          }
+        ],
+        "graph.series_order_dimension": "STATE",
+        "stackable.stack_type": "stacked",
+        "pie.dimension": ["STATE"],
+        "graph.metrics": ["count"]
+      },
+      "collection": null,
+      "metabase_version": "v0.1.37-SNAPSHOT (5b4a5d6)",
+      "parameters": [],
+      "created_at": "2024-10-01T13:37:28.812936+01:00",
+      "parameter_usage_count": 0,
+      "public_uuid": null,
+      "can_delete": false
+    },
+    "data": {
+      "rows": [
+        ["AK", "2022-09-01T00:00:00+01:00", 2],
+        ["AK", "2022-10-01T00:00:00+01:00", 3],
+        ["AK", "2022-11-01T00:00:00Z", 1],
+        ["AK", "2022-12-01T00:00:00Z", 3],
+        ["AK", "2023-01-01T00:00:00Z", 9],
+        ["AK", "2023-02-01T00:00:00Z", 4],
+        ["AL", "2022-09-01T00:00:00+01:00", 1],
+        ["AL", "2022-10-01T00:00:00+01:00", 3],
+        ["AL", "2022-11-01T00:00:00Z", 2],
+        ["AL", "2022-12-01T00:00:00Z", 6],
+        ["AL", "2023-01-01T00:00:00Z", 6],
+        ["AL", "2023-02-01T00:00:00Z", 6],
+        ["AR", "2022-10-01T00:00:00+01:00", 2],
+        ["AR", "2022-11-01T00:00:00Z", 4],
+        ["AR", "2022-12-01T00:00:00Z", 3],
+        ["AR", "2023-01-01T00:00:00Z", 4],
+        ["AR", "2023-02-01T00:00:00Z", 1],
+        ["AZ", "2023-01-01T00:00:00Z", 1],
+        ["AZ", "2023-02-01T00:00:00Z", 1],
+        ["CA", "2022-09-01T00:00:00+01:00", 5],
+        ["CA", "2022-10-01T00:00:00+01:00", 5],
+        ["CA", "2022-11-01T00:00:00Z", 4],
+        ["CA", "2022-12-01T00:00:00Z", 6],
+        ["CA", "2023-01-01T00:00:00Z", 11],
+        ["CA", "2023-02-01T00:00:00Z", 11],
+        ["CO", "2022-09-01T00:00:00+01:00", 4],
+        ["CO", "2022-10-01T00:00:00+01:00", 6],
+        ["CO", "2022-11-01T00:00:00Z", 12],
+        ["CO", "2022-12-01T00:00:00Z", 8],
+        ["CO", "2023-01-01T00:00:00Z", 7],
+        ["CO", "2023-02-01T00:00:00Z", 9],
+        ["CT", "2022-10-01T00:00:00+01:00", 1],
+        ["DE", "2022-10-01T00:00:00+01:00", 1],
+        ["DE", "2022-12-01T00:00:00Z", 1],
+        ["FL", "2022-09-01T00:00:00+01:00", 1],
+        ["FL", "2022-10-01T00:00:00+01:00", 2],
+        ["FL", "2022-11-01T00:00:00Z", 4],
+        ["FL", "2023-01-01T00:00:00Z", 3],
+        ["FL", "2023-02-01T00:00:00Z", 4],
+        ["GA", "2022-09-01T00:00:00+01:00", 1],
+        ["GA", "2022-10-01T00:00:00+01:00", 7],
+        ["GA", "2022-11-01T00:00:00Z", 3],
+        ["GA", "2022-12-01T00:00:00Z", 1],
+        ["GA", "2023-01-01T00:00:00Z", 8],
+        ["GA", "2023-02-01T00:00:00Z", 3],
+        ["IA", "2022-09-01T00:00:00+01:00", 3],
+        ["IA", "2022-10-01T00:00:00+01:00", 4],
+        ["IA", "2022-11-01T00:00:00Z", 5],
+        ["IA", "2022-12-01T00:00:00Z", 5],
+        ["IA", "2023-01-01T00:00:00Z", 10],
+        ["IA", "2023-02-01T00:00:00Z", 7],
+        ["ID", "2022-09-01T00:00:00+01:00", 1],
+        ["ID", "2022-10-01T00:00:00+01:00", 1],
+        ["ID", "2022-11-01T00:00:00Z", 1],
+        ["ID", "2022-12-01T00:00:00Z", 2],
+        ["ID", "2023-01-01T00:00:00Z", 3],
+        ["ID", "2023-02-01T00:00:00Z", 4],
+        ["IL", "2022-09-01T00:00:00+01:00", 1],
+        ["IL", "2022-10-01T00:00:00+01:00", 3],
+        ["IL", "2022-11-01T00:00:00Z", 3],
+        ["IL", "2022-12-01T00:00:00Z", 6],
+        ["IL", "2023-01-01T00:00:00Z", 5],
+        ["IL", "2023-02-01T00:00:00Z", 5],
+        ["KY", "2022-09-01T00:00:00+01:00", 2],
+        ["KY", "2022-10-01T00:00:00+01:00", 5],
+        ["KY", "2022-11-01T00:00:00Z", 5],
+        ["KY", "2022-12-01T00:00:00Z", 4],
+        ["KY", "2023-01-01T00:00:00Z", 4],
+        ["KY", "2023-02-01T00:00:00Z", 3]
+      ],
+      "cols": [
+        {
+          "description": "The state or province of the account’s billing address",
+          "database_type": "CHARACTER",
+          "semantic_type": "type/State",
+          "table_id": 3,
+          "coercion_strategy": null,
+          "name": "STATE",
+          "settings": null,
+          "source": "breakout",
+          "fk_target_field_id": null,
+          "fk_field_id": 43,
+          "field_ref": [
+            "field",
+            48,
+            {
+              "base-type": "type/Text",
+              "source-field": 43
+            }
+          ],
+          "effective_type": "type/Text",
+          "nfc_path": null,
+          "parent_id": null,
+          "id": 48,
+          "position": 7,
+          "visibility_type": "normal",
+          "display_name": "User → State",
+          "fingerprint": {
+            "global": {
+              "distinct-count": 49,
+              "nil%": 0.0
+            },
+            "type": {
+              "type/Text": {
+                "percent-json": 0.0,
+                "percent-url": 0.0,
+                "percent-email": 0.0,
+                "percent-state": 1.0,
+                "average-length": 2.0
+              }
+            }
+          },
+          "base_type": "type/Text",
+          "source_alias": "PEOPLE__via__USER_ID"
+        },
+        {
+          "description": "The date and time an order was submitted.",
+          "database_type": "TIMESTAMP",
+          "semantic_type": "type/CreationTimestamp",
+          "table_id": 5,
+          "coercion_strategy": null,
+          "unit": "month",
+          "name": "CREATED_AT",
+          "settings": null,
+          "source": "breakout",
+          "fk_target_field_id": null,
+          "field_ref": [
+            "field",
+            41,
+            {
+              "base-type": "type/DateTime",
+              "temporal-unit": "month"
+            }
+          ],
+          "effective_type": "type/DateTime",
+          "nfc_path": null,
+          "parent_id": null,
+          "id": 41,
+          "position": 7,
+          "visibility_type": "normal",
+          "display_name": "Created At",
+          "fingerprint": {
+            "global": {
+              "distinct-count": 10001,
+              "nil%": 0.0
+            },
+            "type": {
+              "type/DateTime": {
+                "earliest": "2022-04-30T18:56:13.352Z",
+                "latest": "2026-04-19T14:07:15.657Z"
+              }
+            }
+          },
+          "base_type": "type/DateTime"
+        },
+        {
+          "database_type": "BIGINT",
+          "semantic_type": "type/Quantity",
+          "name": "count",
+          "source": "aggregation",
+          "field_ref": ["aggregation", 0],
+          "effective_type": "type/BigInteger",
+          "aggregation_index": 0,
+          "display_name": "Count",
+          "base_type": "type/BigInteger"
+        }
+      ],
+      "native_form": {
+        "query": "SELECT \"PEOPLE__via__USER_ID\".\"STATE\" AS \"PEOPLE__via__USER_ID__STATE\", DATE_TRUNC('month', \"PUBLIC\".\"ORDERS\".\"CREATED_AT\") AS \"CREATED_AT\", COUNT(*) AS \"count\" FROM \"PUBLIC\".\"ORDERS\" LEFT JOIN \"PUBLIC\".\"PEOPLE\" AS \"PEOPLE__via__USER_ID\" ON \"PUBLIC\".\"ORDERS\".\"USER_ID\" = \"PEOPLE__via__USER_ID\".\"ID\" WHERE (\"PUBLIC\".\"ORDERS\".\"CREATED_AT\" >= timestamp '2022-09-01 00:00:00.000') AND (\"PUBLIC\".\"ORDERS\".\"CREATED_AT\" < timestamp '2023-03-01 00:00:00.000') AND ((\"PEOPLE__via__USER_ID\".\"STATE\" = 'AK') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'AL') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'AR') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'AZ') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'CA') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'CO') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'CT') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'DE') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'FL') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'GA') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'IA') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'ID') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'IL') OR (\"PEOPLE__via__USER_ID\".\"STATE\" = 'KY')) GROUP BY \"PEOPLE__via__USER_ID\".\"STATE\", DATE_TRUNC('month', \"PUBLIC\".\"ORDERS\".\"CREATED_AT\") ORDER BY \"PEOPLE__via__USER_ID\".\"STATE\" ASC, DATE_TRUNC('month', \"PUBLIC\".\"ORDERS\".\"CREATED_AT\") ASC",
+        "params": null
+      },
+      "format-rows?": true,
+      "results_timezone": "Europe/Lisbon",
+      "results_metadata": {
+        "columns": [
+          {
+            "description": "The state or province of the account’s billing address",
+            "semantic_type": "type/State",
+            "coercion_strategy": null,
+            "name": "STATE",
+            "settings": null,
+            "fk_target_field_id": null,
+            "field_ref": [
+              "field",
+              48,
+              {
+                "base-type": "type/Text",
+                "source-field": 43
+              }
+            ],
+            "effective_type": "type/Text",
+            "id": 48,
+            "visibility_type": "normal",
+            "display_name": "User → State",
+            "fingerprint": {
+              "global": {
+                "distinct-count": 49,
+                "nil%": 0.0
+              },
+              "type": {
+                "type/Text": {
+                  "percent-json": 0.0,
+                  "percent-url": 0.0,
+                  "percent-email": 0.0,
+                  "percent-state": 1.0,
+                  "average-length": 2.0
+                }
+              }
+            },
+            "base_type": "type/Text"
+          },
+          {
+            "description": "The date and time an order was submitted.",
+            "semantic_type": "type/CreationTimestamp",
+            "coercion_strategy": null,
+            "unit": "month",
+            "name": "CREATED_AT",
+            "settings": null,
+            "fk_target_field_id": null,
+            "field_ref": [
+              "field",
+              41,
+              {
+                "base-type": "type/DateTime",
+                "temporal-unit": "month"
+              }
+            ],
+            "effective_type": "type/DateTime",
+            "id": 41,
+            "visibility_type": "normal",
+            "display_name": "Created At",
+            "fingerprint": {
+              "global": {
+                "distinct-count": 10001,
+                "nil%": 0.0
+              },
+              "type": {
+                "type/DateTime": {
+                  "earliest": "2022-04-30T18:56:13.352Z",
+                  "latest": "2026-04-19T14:07:15.657Z"
+                }
+              }
+            },
+            "base_type": "type/DateTime"
+          },
+          {
+            "display_name": "Count",
+            "semantic_type": "type/Quantity",
+            "field_ref": ["aggregation", 0],
+            "base_type": "type/BigInteger",
+            "effective_type": "type/BigInteger",
+            "name": "count",
+            "fingerprint": {
+              "global": {
+                "distinct-count": 12,
+                "nil%": 0.0
+              },
+              "type": {
+                "type/Number": {
+                  "min": 1.0,
+                  "q1": 1.8849307066960952,
+                  "q3": 5.5,
+                  "max": 12.0,
+                  "sd": 2.737211604119948,
+                  "avg": 4.086956521739131
+                }
+              }
+            }
+          }
+        ]
+      },
+      "insights": [
+        {
+          "previous-value": 4,
+          "unit": "month",
+          "offset": -377.8969468095498,
+          "last-change": -0.25,
+          "col": "count",
+          "slope": 0.019777876708186145,
+          "last-value": 3,
+          "best-fit": [
+            "*",
+            4.201731368215701e-45,
+            ["exp", ["*", 0.005350764152580669, "x"]]
+          ]
+        }
+      ]
+    }
+  }
+]
diff --git a/frontend/src/metabase/static-viz/components/ComboChart/stories-data/index.ts b/frontend/src/metabase/static-viz/components/ComboChart/stories-data/index.ts
index d6a3293f551..89c4f17c37d 100644
--- a/frontend/src/metabase/static-viz/components/ComboChart/stories-data/index.ts
+++ b/frontend/src/metabase/static-viz/components/ComboChart/stories-data/index.ts
@@ -27,6 +27,9 @@ import barHistogramXScale from "./bar-histogram-x-scale.json";
 import barLinearXScale from "./bar-linear-x-scale.json";
 import barLogYScaleStackedNegative from "./bar-log-y-scale-stacked-negative.json";
 import barLogYScaleStacked from "./bar-log-y-scale-stacked.json";
+import barMaxCategoriesDefault from "./bar-max-categories-default.json";
+import barMaxCategoriesStackedNormalized from "./bar-max-categories-stacked-normalized.json";
+import barMaxCategoriesStacked from "./bar-max-categories-stacked.json";
 import barMinHeightLimit from "./bar-min-height-limit.json";
 import barOrdinalXScaleAutoRotatedLabels from "./bar-ordinal-x-scale-auto-rotated-labels.json";
 import barOrdinalXScale from "./bar-ordinal-x-scale.json";
@@ -226,6 +229,9 @@ export const data = {
   barStackedSeriesLabelsAndTotalsOrdinal,
   barStackedSeriesLabelsNormalizedAutoCompactness,
   barStackedLabelsNullVsZero,
+  barMaxCategoriesDefault,
+  barMaxCategoriesStacked,
+  barMaxCategoriesStackedNormalized,
   barMinHeightLimit,
   comboDataLabelsAutoCompactnessPropagatesFromLine,
   comboDataLabelsAutoCompactnessPropagatesFromTotals,
diff --git a/frontend/src/metabase/visualizations/components/ChartTooltip/EChartsTooltip/EChartsTooltip.tsx b/frontend/src/metabase/visualizations/components/ChartTooltip/EChartsTooltip/EChartsTooltip.tsx
index a6ba65c316c..3e4f33e2c47 100644
--- a/frontend/src/metabase/visualizations/components/ChartTooltip/EChartsTooltip/EChartsTooltip.tsx
+++ b/frontend/src/metabase/visualizations/components/ChartTooltip/EChartsTooltip/EChartsTooltip.tsx
@@ -6,6 +6,10 @@ import { isNotNull } from "metabase/lib/types";
 
 import TooltipStyles from "./EChartsTooltip.module.css";
 
+const getPaddedValuesArray = (values: React.ReactNode[], maxValues: number) => {
+  return Object.assign(Array(maxValues).fill(null), values.slice(0, maxValues));
+};
+
 export interface EChartsTooltipRow {
   /* We pass CSS class with marker colors because setting styles in tooltip rendered by ECharts violates CSP */
   markerColorClass?: string;
@@ -40,14 +44,9 @@ export const EChartsTooltip = ({
   }, 0);
 
   const paddedRows = rows.map(row => {
-    const paddedValues = Object.assign(
-      Array(maxValuesColumns).fill(null),
-      row.values.slice(0, maxValuesColumns),
-    );
-
     return {
       ...row,
-      values: paddedValues,
+      values: getPaddedValuesArray(row.values, maxValuesColumns),
     };
   });
 
@@ -79,6 +78,7 @@ export const EChartsTooltip = ({
           <tfoot data-testid="echarts-tooltip-footer">
             <FooterRow
               {...footer}
+              values={getPaddedValuesArray(footer.values, maxValuesColumns)}
               markerContent={hasMarkers ? <span /> : null}
             />
           </tfoot>
diff --git a/frontend/src/metabase/visualizations/components/ClickActions/ClickActionsView.tsx b/frontend/src/metabase/visualizations/components/ClickActions/ClickActionsView.tsx
index 7d874c2e1fb..8e5306cc365 100644
--- a/frontend/src/metabase/visualizations/components/ClickActions/ClickActionsView.tsx
+++ b/frontend/src/metabase/visualizations/components/ClickActions/ClickActionsView.tsx
@@ -25,7 +25,7 @@ export const ClickActionsView = ({
   const hasOnlyOneSection = sections.length === 1;
 
   return (
-    <Container>
+    <Container data-testid="click-actions-view">
       {sections.map(([sectionKey, actions]) => {
         const sectionTitle = getSectionTitle(sectionKey, actions);
         const contentDirection = getSectionContentDirection(
diff --git a/frontend/src/metabase/visualizations/components/settings/ChartNestedSettingsSeriesMultiple.unit.spec.js b/frontend/src/metabase/visualizations/components/settings/ChartNestedSettingsSeriesMultiple.unit.spec.js
index b45bbc68640..dd85bd52d42 100644
--- a/frontend/src/metabase/visualizations/components/settings/ChartNestedSettingsSeriesMultiple.unit.spec.js
+++ b/frontend/src/metabase/visualizations/components/settings/ChartNestedSettingsSeriesMultiple.unit.spec.js
@@ -4,12 +4,13 @@ import userEvent from "@testing-library/user-event";
 import { renderWithProviders, screen, within } from "__support__/ui";
 import { ChartSettings } from "metabase/visualizations/components/ChartSettings";
 import registerVisualizations from "metabase/visualizations/register";
+import { createMockCard } from "metabase-types/api/mocks";
 
 registerVisualizations();
 
 function getSeries(display, index, changeSeriesName) {
   return {
-    card: {
+    card: createMockCard({
       display,
       visualization_settings: changeSeriesName
         ? {
@@ -19,7 +20,7 @@ function getSeries(display, index, changeSeriesName) {
           }
         : {},
       name: `Test ${index}`,
-    },
+    }),
     data: {
       rows: [
         ["a", 1],
diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingColorPicker/ChartSettingColorPicker.tsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingColorPicker/ChartSettingColorPicker.tsx
index 69811949a1b..ec825a751d1 100644
--- a/frontend/src/metabase/visualizations/components/settings/ChartSettingColorPicker/ChartSettingColorPicker.tsx
+++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingColorPicker/ChartSettingColorPicker.tsx
@@ -24,7 +24,7 @@ export const ChartSettingColorPicker = ({
   accentColorOptions = { main: true, light: true, dark: true, harmony: false },
 }: ChartSettingColorPickerProps) => {
   return (
-    <div className={cx(CS.flex, CS.alignCenter, CS.mb1, className)}>
+    <div className={cx(CS.flex, CS.alignCenter, className)}>
       <ColorSelector
         value={value}
         colors={getAccentColors(accentColorOptions)}
diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingColorsPicker.jsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingColorsPicker.jsx
index 80eae16ce27..5e382e368d3 100644
--- a/frontend/src/metabase/visualizations/components/settings/ChartSettingColorsPicker.jsx
+++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingColorsPicker.jsx
@@ -1,6 +1,8 @@
 /* eslint-disable react/prop-types */
 import { Component } from "react";
 
+import CS from "metabase/css/core/index.css";
+
 import { ChartSettingColorPicker } from "./ChartSettingColorPicker";
 
 export default class ChartSettingColorsPicker extends Component {
@@ -10,6 +12,7 @@ export default class ChartSettingColorsPicker extends Component {
       <div>
         {seriesValues.map((key, index) => (
           <ChartSettingColorPicker
+            className={CS.mb1}
             key={index}
             onChange={color =>
               onChange({
diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldPicker.jsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldPicker.jsx
index 8caa8715de0..2e32f7fa5f2 100644
--- a/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldPicker.jsx
+++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldPicker.jsx
@@ -1,4 +1,5 @@
 /* eslint-disable react/prop-types */
+import { useMemo } from "react";
 import { t } from "ttag";
 import _ from "underscore";
 
@@ -28,6 +29,7 @@ const ChartSettingFieldPicker = ({
   colors,
   series,
   onChangeSeriesColor,
+  fieldSettingWidget = null,
 }) => {
   let columnKey;
   if (value && showColumnSetting && columns) {
@@ -37,6 +39,25 @@ const ChartSettingFieldPicker = ({
     }
   }
 
+  const menuWidgetInfo = useMemo(() => {
+    if (columnKey && showColumnSetting) {
+      return {
+        id: "column_settings",
+        props: {
+          initialKey: columnKey,
+        },
+      };
+    }
+
+    if (fieldSettingWidget) {
+      return {
+        id: fieldSettingWidget,
+      };
+    }
+
+    return null;
+  }, [columnKey, fieldSettingWidget, showColumnSetting]);
+
   let seriesKey;
   if (series && columnKey && showColorPicker) {
     const seriesForColumn = series.find(single => {
@@ -73,21 +94,14 @@ const ChartSettingFieldPicker = ({
         isInitiallyOpen={value === undefined}
         hiddenIcons
       />
-      {columnKey && (
+      {menuWidgetInfo && (
         <SettingsButton
           onlyIcon
           icon="ellipsis"
           onClick={e => {
-            onShowWidget(
-              {
-                id: "column_settings",
-                props: {
-                  initialKey: columnKey,
-                },
-              },
-              e.target,
-            );
+            onShowWidget(menuWidgetInfo, e.target);
           }}
+          data-testid={`settings-${value}`}
         />
       )}
       {onRemove && (
diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldPicker.unit.spec.js b/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldPicker.unit.spec.js
index 7616531c2db..ef81f1493ce 100644
--- a/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldPicker.unit.spec.js
+++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldPicker.unit.spec.js
@@ -4,19 +4,20 @@ import { within } from "@testing-library/react";
 import { renderWithProviders, screen } from "__support__/ui";
 import { ChartSettings } from "metabase/visualizations/components/ChartSettings";
 import registerVisualizations from "metabase/visualizations/register";
+import { createMockCard } from "metabase-types/api/mocks";
 
 registerVisualizations();
 
 function getSeries(metricColumnProps) {
   return [
     {
-      card: {
+      card: createMockCard({
         display: "line",
         visualization_settings: {
           "graph.dimensions": ["FOO"],
           "graph.metrics": ["BAR"],
         },
-      },
+      }),
       data: {
         rows: [
           ["a", 1],
diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldsPicker.jsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldsPicker.jsx
index f5ffdaa3c3e..79fc927e22e 100644
--- a/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldsPicker.jsx
+++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingFieldsPicker.jsx
@@ -17,6 +17,7 @@ const ChartSettingFieldsPicker = ({
   addAnother,
   showColumnSetting,
   showColumnSettingForIndicies,
+  fieldSettingWidgets = [],
   ...props
 }) => {
   const handleDragEnd = ({ source, destination }) => {
@@ -93,6 +94,7 @@ const ChartSettingFieldsPicker = ({
                                 : null
                             }
                             showDragHandle={fields.length > 1}
+                            fieldSettingWidget={fieldSettingWidgets[fieldIndex]}
                           />
                         </div>
                       )}
diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingInputNumeric.tsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingInputNumeric.tsx
index f692dc2bb7e..715af5d8c67 100644
--- a/frontend/src/metabase/visualizations/components/settings/ChartSettingInputNumeric.tsx
+++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingInputNumeric.tsx
@@ -3,6 +3,7 @@ import { useState } from "react";
 import _ from "underscore";
 
 import { ChartSettingNumericInput } from "./ChartSettingInputNumeric.styled";
+import type { ChartSettingWidgetProps } from "./types";
 
 const ALLOWED_CHARS = [
   "0",
@@ -22,10 +23,7 @@ const ALLOWED_CHARS = [
 
 // Note: there are more props than these that are provided by the viz settings
 // code, we just don't have types for them here.
-interface ChartSettingInputProps {
-  value: number | undefined;
-  onChange: (value: number | undefined) => void;
-  onChangeSettings: () => void;
+interface ChartSettingInputProps extends ChartSettingWidgetProps<number> {
   options?: {
     isInteger?: boolean;
     isNonNegative?: boolean;
diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingMaxCategories.tsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingMaxCategories.tsx
new file mode 100644
index 00000000000..9dd8d0fde87
--- /dev/null
+++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingMaxCategories.tsx
@@ -0,0 +1,85 @@
+import { useCallback } from "react";
+import { t } from "ttag";
+
+import { Checkbox, Select, Stack, Text } from "metabase/ui";
+import type { VisualizationSettings } from "metabase-types/api";
+
+import { ChartSettingInputNumeric } from "./ChartSettingInputNumeric";
+import type { ChartSettingWidgetProps } from "./types";
+
+type AggregationFunction = Exclude<
+  VisualizationSettings["graph.other_category_aggregation_fn"],
+  undefined
+>;
+
+export interface ChartSettingMaxCategoriesProps
+  extends ChartSettingWidgetProps<number> {
+  isEnabled?: boolean;
+  aggregationFunction: AggregationFunction;
+}
+
+export const ChartSettingMaxCategories = ({
+  isEnabled,
+  aggregationFunction,
+  ...props
+}: ChartSettingMaxCategoriesProps) => {
+  const { onChangeSettings } = props;
+
+  const handleToggleMaxNumberOfSeries = useCallback(
+    (value: boolean) => {
+      onChangeSettings({ "graph.max_categories_enabled": value });
+    },
+    [onChangeSettings],
+  );
+
+  const handleAggregationFunctionChange = useCallback(
+    (value: string | null) => {
+      if (value) {
+        onChangeSettings({
+          "graph.other_category_aggregation_fn": value as AggregationFunction,
+        });
+      }
+    },
+    [onChangeSettings],
+  );
+
+  return (
+    <Stack spacing="md">
+      <Checkbox
+        checked={isEnabled}
+        label={t`Enforce maximum number of series`}
+        onChange={e => handleToggleMaxNumberOfSeries(e.target.checked)}
+      />
+      <ChartSettingInputNumeric
+        {...props}
+        data-testid="graph-max-categories-input"
+      />
+      <Text>{t`Series after this number will be grouped into "Other"`}</Text>
+      <div>
+        <Text
+          component="label"
+          htmlFor="aggregationFunction"
+          color="var(--mb-color-text-dark)"
+          fz="sm"
+          mb="sm"
+        >{t`Aggregation method for Other group`}</Text>
+        <Select
+          name="aggregationFunction"
+          value={aggregationFunction}
+          data={AGGREGATION_FN_OPTIONS}
+          onChange={handleAggregationFunctionChange}
+          data-testid="graph-other-category-aggregation-fn-picker"
+        />
+      </div>
+    </Stack>
+  );
+};
+
+const AGGREGATION_FN_OPTIONS = [
+  { label: t`Sum`, value: "sum" },
+  { label: t`Average`, value: "avg" },
+  { label: t`Median`, value: "median" },
+  { label: t`Standard deviation`, value: "stddev" },
+  { label: t`Min`, value: "min" },
+  { label: t`Max`, value: "max" },
+];
diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingOrderedItems/ChartSettingOrderedItems.tsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingOrderedItems/ChartSettingOrderedItems.tsx
index 6869dd3b4d0..1e78b76f999 100644
--- a/frontend/src/metabase/visualizations/components/settings/ChartSettingOrderedItems/ChartSettingOrderedItems.tsx
+++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingOrderedItems/ChartSettingOrderedItems.tsx
@@ -1,7 +1,10 @@
 import { PointerSensor, useSensor } from "@dnd-kit/core";
 import { useCallback } from "react";
 
-import type { DragEndEvent } from "metabase/core/components/Sortable";
+import type {
+  DragEndEvent,
+  SortableDivider,
+} from "metabase/core/components/Sortable";
 import { Sortable, SortableList } from "metabase/core/components/Sortable";
 import type { AccentColorOptions } from "metabase/lib/colors/types";
 import type { IconProps } from "metabase/ui";
@@ -13,6 +16,7 @@ export interface SortableItem {
   color?: string;
   icon?: IconProps["name"];
   isOther?: boolean;
+  hideSettings?: boolean;
 }
 
 interface SortableColumnFunctions<T> {
@@ -32,6 +36,7 @@ interface ChartSettingOrderedItemsProps<T extends SortableItem>
   removeIcon?: IconProps["name"];
   accentColorOptions?: AccentColorOptions;
   getItemColor?: (item: SortableItem) => string | undefined;
+  dividers?: SortableDivider[];
 }
 
 export function ChartSettingOrderedItems<T extends SortableItem>({
@@ -48,6 +53,7 @@ export function ChartSettingOrderedItems<T extends SortableItem>({
   removeIcon,
   accentColorOptions,
   getItemColor = item => item.color,
+  dividers = [],
 }: ChartSettingOrderedItemsProps<T>) {
   const isDragDisabled = items.length < 1;
   const pointerSensor = useSensor(PointerSensor, {
@@ -66,7 +72,7 @@ export function ChartSettingOrderedItems<T extends SortableItem>({
           <ColumnItem
             title={getItemName(item)}
             onEdit={
-              onEdit
+              onEdit && !item.hideSettings
                 ? (targetElement: HTMLElement) => onEdit(item, targetElement)
                 : undefined
             }
@@ -114,6 +120,7 @@ export function ChartSettingOrderedItems<T extends SortableItem>({
       items={items}
       onSortEnd={onSortEnd}
       sensors={[pointerSensor]}
+      dividers={dividers}
     />
   );
 }
diff --git a/frontend/src/metabase/visualizations/components/settings/ChartSettingSeriesOrder.tsx b/frontend/src/metabase/visualizations/components/settings/ChartSettingSeriesOrder.tsx
index 2ce266ac9e3..19b6606f161 100644
--- a/frontend/src/metabase/visualizations/components/settings/ChartSettingSeriesOrder.tsx
+++ b/frontend/src/metabase/visualizations/components/settings/ChartSettingSeriesOrder.tsx
@@ -4,11 +4,15 @@ import { useCallback, useMemo, useState } from "react";
 import { t } from "ttag";
 import _ from "underscore";
 
+import ColorSelector from "metabase/core/components/ColorSelector";
 import type { DragEndEvent } from "metabase/core/components/Sortable";
+import { color } from "metabase/lib/colors";
+import { getAccentColors } from "metabase/lib/colors/groups";
 import type { AccentColorOptions } from "metabase/lib/colors/types";
 import { NULL_DISPLAY_VALUE } from "metabase/lib/constants";
+import { getEventTarget } from "metabase/lib/dom";
 import { isEmpty } from "metabase/lib/validate";
-import { Button, Select } from "metabase/ui";
+import { Button, Flex, Group, Icon, Select, Text } from "metabase/ui";
 import type { Series } from "metabase-types/api";
 
 import {
@@ -28,13 +32,14 @@ export interface SortableItem {
   name: string;
   color?: string;
   hidden?: boolean;
+  hideSettings?: boolean;
 }
 
 interface ChartSettingSeriesOrderProps {
   onChange: (rows: SortableItem[]) => void;
   value: SortableItem[];
   onShowWidget: (
-    widget: { props: { seriesKey: string } },
+    widget: { id?: string; props?: { seriesKey: string } },
     ref: HTMLElement | undefined,
   ) => void;
   series: Series;
@@ -45,6 +50,11 @@ interface ChartSettingSeriesOrderProps {
   getItemColor?: (item: SortableChartSettingOrderedItem) => string | undefined;
   addButtonLabel?: string;
   searchPickerPlaceholder?: string;
+  groupedAfterIndex?: number;
+  otherColor?: string;
+  otherSettingWidgetId?: string;
+  onOtherColorChange?: (newColor: string) => void;
+  truncateAfter?: number;
 }
 
 export const ChartSettingSeriesOrder = ({
@@ -58,10 +68,16 @@ export const ChartSettingSeriesOrder = ({
   onSortEnd,
   getItemColor,
   accentColorOptions,
+  otherColor,
+  groupedAfterIndex = Infinity,
+  otherSettingWidgetId,
+  truncateAfter = Infinity,
+  onOtherColorChange,
 }: ChartSettingSeriesOrderProps) => {
+  const [isListTruncated, setIsListTruncated] = useState<boolean>(true);
   const [isSeriesPickerVisible, setSeriesPickerVisible] = useState(false);
 
-  const [visibleItems, hiddenItems] = useMemo(
+  const [items, hiddenItems] = useMemo(
     () =>
       _.partition(
         orderedItems.filter(item => !item.hidden),
@@ -69,6 +85,27 @@ export const ChartSettingSeriesOrder = ({
       ),
     [orderedItems],
   );
+  const itemsAfterGrouping = useMemo(() => {
+    return items.map((item, index) => {
+      if (index < groupedAfterIndex) {
+        return item;
+      }
+      return {
+        ...item,
+        color: undefined,
+        hideSettings: true,
+      };
+    });
+  }, [groupedAfterIndex, items]);
+
+  const [visibleItems, truncatedItems] = useMemo(
+    () =>
+      _.partition(
+        itemsAfterGrouping,
+        (_item, index) => !isListTruncated || index < truncateAfter,
+      ),
+    [isListTruncated, itemsAfterGrouping, truncateAfter],
+  );
 
   const canAddSeries = hiddenItems.length > 0;
 
@@ -133,6 +170,52 @@ export const ChartSettingSeriesOrder = ({
 
   const getId = useCallback((item: SortableItem) => item.key, []);
 
+  const handleOtherSeriesSettingsClick = useCallback(
+    (e: React.MouseEvent) => {
+      onShowWidget({ id: otherSettingWidgetId }, getEventTarget(e));
+    },
+    [onShowWidget, otherSettingWidgetId],
+  );
+
+  const dividers = useMemo(() => {
+    return [
+      {
+        afterIndex: groupedAfterIndex,
+        renderFn: () => (
+          <Flex justify="space-between" px={4}>
+            <Group p={4} spacing="sm">
+              <ColorSelector
+                value={otherColor ?? color("text-light")}
+                colors={[
+                  ...getAccentColors(),
+                  color("text-light"),
+                  color("text-medium"),
+                  color("text-dark"),
+                ]}
+                onChange={onOtherColorChange}
+                pillSize="small"
+              />
+              <Text truncate fw="bold">{t`Other`}</Text>
+            </Group>
+            <Button
+              compact
+              color="text-medium"
+              variant="subtle"
+              leftIcon={<Icon name="gear" />}
+              aria-label={t`Other series settings`}
+              onClick={handleOtherSeriesSettingsClick}
+            />
+          </Flex>
+        ),
+      },
+    ];
+  }, [
+    groupedAfterIndex,
+    handleOtherSeriesSettingsClick,
+    onOtherColorChange,
+    otherColor,
+  ]);
+
   return (
     <ChartSettingOrderedSimpleRoot>
       {orderedItems.length > 0 ? (
@@ -149,7 +232,18 @@ export const ChartSettingSeriesOrder = ({
             removeIcon="close"
             accentColorOptions={accentColorOptions}
             getItemColor={getItemColor}
+            dividers={dividers}
           />
+          {truncatedItems.length > 0 ? (
+            <div>
+              <Button
+                variant="subtle"
+                onClick={() => setIsListTruncated(false)}
+              >
+                {t`${truncatedItems.length} more series`}
+              </Button>
+            </div>
+          ) : null}
           {canAddSeries && !isSeriesPickerVisible && (
             <Button
               variant="subtle"
diff --git a/frontend/src/metabase/visualizations/components/settings/types.ts b/frontend/src/metabase/visualizations/components/settings/types.ts
new file mode 100644
index 00000000000..4ea4317c698
--- /dev/null
+++ b/frontend/src/metabase/visualizations/components/settings/types.ts
@@ -0,0 +1,7 @@
+import type { VisualizationSettings } from "metabase-types/api";
+
+export interface ChartSettingWidgetProps<TValue> {
+  value: TValue | undefined;
+  onChange: (value?: TValue | null) => void;
+  onChangeSettings: (settings: Partial<VisualizationSettings>) => void;
+}
diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/constants/dataset.ts b/frontend/src/metabase/visualizations/echarts/cartesian/constants/dataset.ts
index a8a1867f897..ca4cf5c3625 100644
--- a/frontend/src/metabase/visualizations/echarts/cartesian/constants/dataset.ts
+++ b/frontend/src/metabase/visualizations/echarts/cartesian/constants/dataset.ts
@@ -15,6 +15,9 @@ export const NEGATIVE_BAR_DATA_LABEL_KEY_SUFFIX = `${NULL_CHAR}_negative_bar_dat
 // Key of x-axis values
 export const X_AXIS_DATA_KEY = `${NULL_CHAR}_x` as const;
 
+// Key for the "other" series created by the `graph.max_categories` setting
+export const OTHER_DATA_KEY = `${NULL_CHAR}_other` as const;
+
 // In some cases a datum in `chartModel.transformedDataset` may include this
 // key, its value is equal to the index of that same datum in the original
 // dataset (e.g. `chartModel.dataset`)
diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/model/dataset.ts b/frontend/src/metabase/visualizations/echarts/cartesian/model/dataset.ts
index eafa4177d5d..e4ce18e2d27 100644
--- a/frontend/src/metabase/visualizations/echarts/cartesian/model/dataset.ts
+++ b/frontend/src/metabase/visualizations/echarts/cartesian/model/dataset.ts
@@ -8,6 +8,7 @@ import {
   ECHARTS_CATEGORY_AXIS_NULL_VALUE,
   NEGATIVE_STACK_TOTAL_DATA_KEY,
   ORIGINAL_INDEX_DATA_KEY,
+  OTHER_DATA_KEY,
   POSITIVE_STACK_TOTAL_DATA_KEY,
   X_AXIS_DATA_KEY,
 } from "metabase/visualizations/echarts/cartesian/constants/dataset";
@@ -47,6 +48,7 @@ import type { ShowWarning } from "../../types";
 import { tryGetDate } from "../utils/timeseries";
 
 import { isCategoryAxis, isNumericAxis, isTimeSeriesAxis } from "./guards";
+import { getAggregatedOtherSeriesValue } from "./other-series";
 import { getBarSeriesDataLabelKey, getColumnScaling } from "./util";
 
 /**
@@ -334,6 +336,23 @@ const getStackedAreasInterpolateTransform = (
   };
 };
 
+function getOtherSeriesTransform(
+  groupedSeriesModels: SeriesModel[],
+  settings: ComputedVisualizationSettings,
+): ConditionalTransform {
+  return {
+    condition: groupedSeriesModels.length > 0,
+    fn: datum => ({
+      ...datum,
+      [OTHER_DATA_KEY]: getAggregatedOtherSeriesValue(
+        groupedSeriesModels,
+        settings["graph.other_category_aggregation_fn"],
+        datum,
+      ),
+    }),
+  };
+}
+
 function getStackedValueTransformFunction(
   seriesDataKeys: DataKey[],
   valueTransform: (value: number) => number | null,
@@ -697,6 +716,7 @@ export const applyVisualizationSettingsDataTransformations = (
   stackModels: StackModel[],
   xAxisModel: XAxisModel,
   seriesModels: SeriesModel[],
+  groupedSeriesModels: SeriesModel[],
   yAxisScaleTransforms: NumericAxisScaleTransforms,
   settings: ComputedVisualizationSettings,
   showWarning?: ShowWarning,
@@ -734,6 +754,7 @@ export const applyVisualizationSettingsDataTransformations = (
 
   return transformDataset(dataset, [
     getNullReplacerTransform(settings, seriesModels),
+    getOtherSeriesTransform(groupedSeriesModels, settings),
     {
       condition: settings["stackable.stack_type"] === "normalized",
       fn: getNormalizedDatasetTransform(stackModels),
@@ -852,13 +873,12 @@ export const getSortedSeriesModels = (
           seriesModel.vizSettingsKey === orderSetting.key &&
           !usedDataKeys.has(seriesModel.dataKey),
       );
-      if (foundSeries === undefined) {
-        throw new TypeError("Series not found");
+      if (foundSeries) {
+        usedDataKeys.add(foundSeries.dataKey);
       }
-
-      usedDataKeys.add(foundSeries.dataKey);
       return foundSeries;
-    });
+    })
+    .filter(isNotNull);
 
   // On stacked charts we reverse the order of series so that the series
   // order in the sidebar matches series order on the chart.
diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/model/dataset.unit.spec.ts b/frontend/src/metabase/visualizations/echarts/cartesian/model/dataset.unit.spec.ts
index abc4303115d..defa3a8b2e7 100644
--- a/frontend/src/metabase/visualizations/echarts/cartesian/model/dataset.unit.spec.ts
+++ b/frontend/src/metabase/visualizations/echarts/cartesian/model/dataset.unit.spec.ts
@@ -303,6 +303,7 @@ describe("dataset transform functions", () => {
         [],
         xAxisModel,
         seriesModels,
+        [],
         yAxisScaleTransforms,
         createMockComputedVisualizationSettings({
           "stackable.stack_type": "stacked",
@@ -341,6 +342,7 @@ describe("dataset transform functions", () => {
         ],
         xAxisModel,
         seriesModels,
+        [],
         yAxisScaleTransforms,
         createMockComputedVisualizationSettings({
           "stackable.stack_type": "normalized",
@@ -380,6 +382,7 @@ describe("dataset transform functions", () => {
         [],
         xAxisModel,
         seriesModels,
+        [],
         yAxisScaleTransforms,
         createMockComputedVisualizationSettings({
           series: (key: LegacySeriesSettingsObjectKey) => ({
@@ -434,6 +437,7 @@ describe("dataset transform functions", () => {
           [],
           xAxisModel,
           [createMockSeriesModel({ dataKey: "series1" })],
+          [],
           yAxisScaleTransforms,
           createMockComputedVisualizationSettings({
             series: () => ({
@@ -465,6 +469,7 @@ describe("dataset transform functions", () => {
           [],
           { ...xAxisModel, intervalsCount: 10001 },
           [createMockSeriesModel({ dataKey: "series1" })],
+          [],
           yAxisScaleTransforms,
           createMockComputedVisualizationSettings({
             series: () => ({
@@ -511,6 +516,7 @@ describe("dataset transform functions", () => {
           [],
           xAxisModel,
           seriesModels,
+          [],
           yAxisScaleTransforms,
           createMockComputedVisualizationSettings(),
         );
@@ -530,6 +536,7 @@ describe("dataset transform functions", () => {
             [],
             xAxisModel,
             seriesModels,
+            [],
             yAxisScaleTransforms,
             createMockComputedVisualizationSettings(),
           ),
@@ -543,6 +550,7 @@ describe("dataset transform functions", () => {
         [],
         xAxisModel,
         seriesModels,
+        [],
         yAxisScaleTransforms,
         createMockVisualizationSettings({
           series: (key: LegacySeriesSettingsObjectKey) => ({
diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/model/guards.ts b/frontend/src/metabase/visualizations/echarts/cartesian/model/guards.ts
index 56f2f4c9d85..cea27c4b9e1 100644
--- a/frontend/src/metabase/visualizations/echarts/cartesian/model/guards.ts
+++ b/frontend/src/metabase/visualizations/echarts/cartesian/model/guards.ts
@@ -1,8 +1,8 @@
 import type {
+  BaseSeriesModel,
   BreakoutSeriesModel,
   CategoryXAxisModel,
   NumericXAxisModel,
-  SeriesModel,
   TimeSeriesInterval,
   TimeSeriesXAxisModel,
   XAxisModel,
@@ -27,7 +27,7 @@ export const isCategoryAxis = (
 };
 
 export const isBreakoutSeries = (
-  seriesModel: SeriesModel,
+  seriesModel: BaseSeriesModel,
 ): seriesModel is BreakoutSeriesModel => {
   return "breakoutColumn" in seriesModel;
 };
diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/model/index.ts b/frontend/src/metabase/visualizations/echarts/cartesian/model/index.ts
index 63a6a581e4f..fbbb3ec8e62 100644
--- a/frontend/src/metabase/visualizations/echarts/cartesian/model/index.ts
+++ b/frontend/src/metabase/visualizations/echarts/cartesian/model/index.ts
@@ -1,3 +1,4 @@
+import { OTHER_DATA_KEY } from "metabase/visualizations/echarts/cartesian/constants/dataset";
 import {
   getXAxisModel,
   getYAxesModels,
@@ -28,6 +29,10 @@ import type { RawSeries, SingleSeries } from "metabase-types/api";
 
 import type { ShowWarning } from "../../types";
 
+import {
+  createOtherGroupSeriesModel,
+  groupSeriesIntoOther,
+} from "./other-series";
 import { getStackModels } from "./stack";
 import { getAxisTransforms } from "./transforms";
 import { getTrendLines } from "./trend-line";
@@ -93,11 +98,6 @@ export const getCartesianChartModel = (
     settings,
   );
 
-  // We currently ignore sorting and visibility settings on combined cards
-  const seriesModels = hasMultipleCards
-    ? unsortedSeriesModels
-    : getSortedSeriesModels(unsortedSeriesModels, settings);
-
   const unsortedDataset = getJoinedCardsDataset(
     rawSeries,
     cardsColumns,
@@ -108,7 +108,27 @@ export const getCartesianChartModel = (
     settings["graph.x_axis.scale"],
     showWarning,
   );
-  const scaledDataset = scaleDataset(dataset, seriesModels, settings);
+
+  const sortedSeriesModels = hasMultipleCards
+    ? unsortedSeriesModels
+    : getSortedSeriesModels(unsortedSeriesModels, settings);
+
+  const scaledDataset = scaleDataset(dataset, sortedSeriesModels, settings);
+
+  const { ungroupedSeriesModels: seriesModels, groupedSeriesModels } =
+    groupSeriesIntoOther(sortedSeriesModels, settings);
+
+  const [sampleGroupedModel] = groupedSeriesModels;
+  if (sampleGroupedModel) {
+    seriesModels.push(
+      createOtherGroupSeriesModel(
+        sampleGroupedModel.column,
+        sampleGroupedModel.columnIndex,
+        settings,
+        !hiddenSeries.includes(OTHER_DATA_KEY),
+      ),
+    );
+  }
 
   const xAxisModel = getXAxisModel(
     dimensionModel,
@@ -128,6 +148,7 @@ export const getCartesianChartModel = (
     stackModels,
     xAxisModel,
     seriesModels,
+    groupedSeriesModels,
     yAxisScaleTransforms,
     settings,
     showWarning,
@@ -186,5 +207,6 @@ export const getCartesianChartModel = (
     seriesLabelsFormatters,
     stackedLabelsFormatters,
     dataDensity,
+    groupedSeriesModels,
   };
 };
diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/model/legend.ts b/frontend/src/metabase/visualizations/echarts/cartesian/model/legend.ts
index 792a155808a..d6c22da616c 100644
--- a/frontend/src/metabase/visualizations/echarts/cartesian/model/legend.ts
+++ b/frontend/src/metabase/visualizations/echarts/cartesian/model/legend.ts
@@ -1,8 +1,8 @@
 import { isBreakoutSeries } from "./guards";
-import type { LegendItem, SeriesModel } from "./types";
+import type { BaseSeriesModel, LegendItem } from "./types";
 
 export const getLegendItems = (
-  seriesModels: SeriesModel[],
+  seriesModels: BaseSeriesModel[],
   showAllLegendItems: boolean = false,
 ): LegendItem[] => {
   if (
diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/model/other-series.ts b/frontend/src/metabase/visualizations/echarts/cartesian/model/other-series.ts
new file mode 100644
index 00000000000..063c5068a6f
--- /dev/null
+++ b/frontend/src/metabase/visualizations/echarts/cartesian/model/other-series.ts
@@ -0,0 +1,154 @@
+import { t } from "ttag";
+
+import { checkNumber } from "metabase/lib/types";
+import { isEmpty } from "metabase/lib/validate";
+import { SERIES_SETTING_KEY } from "metabase/visualizations/shared/settings/series";
+import type { ComputedVisualizationSettings } from "metabase/visualizations/types";
+import type { AggregationType, DatasetColumn } from "metabase-types/api";
+
+import { OTHER_DATA_KEY } from "../constants/dataset";
+
+import type { Datum, RegularSeriesModel, SeriesModel } from "./types";
+
+export function groupSeriesIntoOther(
+  seriesModels: SeriesModel[],
+  settings: ComputedVisualizationSettings,
+): {
+  ungroupedSeriesModels: SeriesModel[];
+  groupedSeriesModels: SeriesModel[];
+} {
+  const maxCategories = settings["graph.max_categories"];
+
+  if (
+    !settings["graph.max_categories_enabled"] ||
+    !maxCategories ||
+    maxCategories <= 0 ||
+    seriesModels.length <= maxCategories
+  ) {
+    return {
+      ungroupedSeriesModels: seriesModels,
+      groupedSeriesModels: [],
+    };
+  }
+
+  const isReversed = !isEmpty(settings["stackable.stack_type"]);
+  const _seriesModels = isReversed ? seriesModels.toReversed() : seriesModels;
+
+  const ungroupedSeriesModels = _seriesModels.slice(
+    0,
+    settings["graph.max_categories"],
+  );
+  if (isReversed) {
+    ungroupedSeriesModels.reverse();
+  }
+
+  const groupedSeriesModels = _seriesModels.slice(
+    settings["graph.max_categories"],
+  );
+
+  return {
+    ungroupedSeriesModels,
+    groupedSeriesModels,
+  };
+}
+
+export const createOtherGroupSeriesModel = (
+  column: DatasetColumn,
+  columnIndex: number,
+  settings: ComputedVisualizationSettings,
+  isVisible: boolean,
+): RegularSeriesModel => {
+  const customName = settings[SERIES_SETTING_KEY]?.[OTHER_DATA_KEY]?.title;
+  const name = customName ?? t`Other`;
+
+  return {
+    name,
+    dataKey: OTHER_DATA_KEY,
+    color: settings["graph.other_category_color"],
+    visible: isVisible,
+    column,
+    columnIndex,
+    vizSettingsKey: OTHER_DATA_KEY,
+    legacySeriesSettingsObjectKey: {
+      card: {
+        _seriesKey: OTHER_DATA_KEY,
+      },
+    },
+    tooltipName: name,
+  };
+};
+
+export const getAggregatedOtherSeriesValue = (
+  seriesModels: SeriesModel[],
+  aggregationType: AggregationType = "sum",
+  datum: Datum,
+): number => {
+  const aggregation = AGGREGATION_FN_MAP[aggregationType];
+  const values = seriesModels.map(model =>
+    checkNumber(datum[model.dataKey] ?? 0),
+  );
+  return aggregation.fn(values);
+};
+
+export const getOtherSeriesAggregationLabel = (
+  aggregationType: AggregationType = "sum",
+) => AGGREGATION_FN_MAP[aggregationType].label;
+
+const sum = (values: number[]) => values.reduce((sum, value) => sum + value, 0);
+
+const AGGREGATION_FN_MAP: Record<
+  AggregationType,
+  { fn: (values: number[]) => number; label: string }
+> = {
+  count: {
+    label: t`Total`,
+    fn: sum,
+  },
+  sum: {
+    label: t`Total`,
+    fn: sum,
+  },
+  "cum-sum": {
+    label: t`Total`,
+    fn: sum,
+  },
+  "cum-count": {
+    label: t`Total`,
+    fn: sum,
+  },
+  avg: {
+    label: t`Average`,
+    fn: values => sum(values) / values.length,
+  },
+  distinct: {
+    label: t`Distinct values`,
+    fn: values => new Set(values).size,
+  },
+  min: {
+    label: t`Min`,
+    fn: values => Math.min(...values),
+  },
+  max: {
+    label: t`Max`,
+    fn: values => Math.max(...values),
+  },
+  median: {
+    label: t`Median`,
+    fn: values => {
+      const sortedValues = values.sort((a, b) => a - b);
+      const middleIndex = Math.floor(sortedValues.length / 2);
+      return sortedValues.length % 2
+        ? sortedValues[middleIndex]
+        : (sortedValues[middleIndex - 1] + sortedValues[middleIndex]) / 2;
+    },
+  },
+  stddev: {
+    label: t`Standard deviation`,
+    fn: values => {
+      const mean = sum(values) / values.length;
+      const squaredDifferences = values.map(v => (v - mean) ** 2);
+      const variance = sum(squaredDifferences) / values.length;
+      return Math.sqrt(variance);
+    },
+  },
+};
diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/model/series.ts b/frontend/src/metabase/visualizations/echarts/cartesian/model/series.ts
index 4049a1c3f94..96a964e2982 100644
--- a/frontend/src/metabase/visualizations/echarts/cartesian/model/series.ts
+++ b/frontend/src/metabase/visualizations/echarts/cartesian/model/series.ts
@@ -1,5 +1,3 @@
-import _ from "underscore";
-
 import { NULL_DISPLAY_VALUE } from "metabase/lib/constants";
 import { formatValue } from "metabase/lib/formatting";
 import type { OptionsType } from "metabase/lib/formatting/types";
diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/model/types.ts b/frontend/src/metabase/visualizations/echarts/cartesian/model/types.ts
index 4c0984c3d13..770376fb172 100644
--- a/frontend/src/metabase/visualizations/echarts/cartesian/model/types.ts
+++ b/frontend/src/metabase/visualizations/echarts/cartesian/model/types.ts
@@ -234,6 +234,9 @@ export type BaseCartesianChartModel = {
 
   trendLinesModel?: TrendLinesModel;
   seriesLabelsFormatters: SeriesFormatters;
+
+  // For `graph.max_categories` setting
+  groupedSeriesModels?: SeriesModel[];
 };
 
 export type CartesianChartModel = BaseCartesianChartModel & {
diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/option/index.ts b/frontend/src/metabase/visualizations/echarts/cartesian/option/index.ts
index f75c987ae86..81530908709 100644
--- a/frontend/src/metabase/visualizations/echarts/cartesian/option/index.ts
+++ b/frontend/src/metabase/visualizations/echarts/cartesian/option/index.ts
@@ -3,6 +3,7 @@ import type { OptionSourceData } from "echarts/types/src/util/types";
 
 import {
   NEGATIVE_STACK_TOTAL_DATA_KEY,
+  OTHER_DATA_KEY,
   POSITIVE_STACK_TOTAL_DATA_KEY,
   X_AXIS_DATA_KEY,
 } from "metabase/visualizations/echarts/cartesian/constants/dataset";
@@ -84,6 +85,7 @@ export const getCartesianChartOption = (
   // dataset option
   const dimensions = [
     X_AXIS_DATA_KEY,
+    OTHER_DATA_KEY,
     POSITIVE_STACK_TOTAL_DATA_KEY,
     NEGATIVE_STACK_TOTAL_DATA_KEY,
     ...chartModel.seriesModels.map(seriesModel => [
diff --git a/frontend/src/metabase/visualizations/echarts/cartesian/scatter/model/index.ts b/frontend/src/metabase/visualizations/echarts/cartesian/scatter/model/index.ts
index 067877f2d34..79798ec4e1e 100644
--- a/frontend/src/metabase/visualizations/echarts/cartesian/scatter/model/index.ts
+++ b/frontend/src/metabase/visualizations/echarts/cartesian/scatter/model/index.ts
@@ -102,6 +102,7 @@ export function getScatterPlotModel(
     [],
     xAxisModel,
     seriesModels,
+    [],
     yAxisScaleTransforms,
     settings,
     showWarning,
diff --git a/frontend/src/metabase/visualizations/lib/settings/graph.js b/frontend/src/metabase/visualizations/lib/settings/graph.js
index d1541aa8bb6..404b2ce78bd 100644
--- a/frontend/src/metabase/visualizations/lib/settings/graph.js
+++ b/frontend/src/metabase/visualizations/lib/settings/graph.js
@@ -1,17 +1,16 @@
 import { t } from "ttag";
 import _ from "underscore";
 
+import { color } from "metabase/lib/colors";
 import {
   getMaxDimensionsSupported,
   getMaxMetricsSupported,
 } from "metabase/visualizations";
+import { ChartSettingMaxCategories } from "metabase/visualizations/components/settings/ChartSettingMaxCategories";
 import { ChartSettingSeriesOrder } from "metabase/visualizations/components/settings/ChartSettingSeriesOrder";
 import { dimensionIsNumeric } from "metabase/visualizations/lib/numeric";
 import { columnSettings } from "metabase/visualizations/lib/settings/column";
-import {
-  keyForSingleSeries,
-  seriesSetting,
-} from "metabase/visualizations/lib/settings/series";
+import { seriesSetting } from "metabase/visualizations/lib/settings/series";
 import { getOptionFromColumn } from "metabase/visualizations/lib/settings/utils";
 import { dimensionIsTimeseries } from "metabase/visualizations/lib/timeseries";
 import { MAX_SERIES, columnsAreValid } from "metabase/visualizations/lib/utils";
@@ -39,6 +38,7 @@ import {
   getDefaultYAxisTitle,
   getIsXAxisLabelEnabledDefault,
   getIsYAxisLabelEnabledDefault,
+  getSeriesModelsForSettings,
   getSeriesOrderDimensionSetting,
   getSeriesOrderVisibilitySettings,
   getYAxisAutoRangeDefault,
@@ -66,6 +66,13 @@ function canHaveDataLabels(series, vizSettings) {
   return vizSettings["stackable.stack_type"] !== "normalized" || !areAllAreas;
 }
 
+const areAllBars = (series, settings) =>
+  getSeriesDisplays(series, settings).every(display => display === "bar");
+
+const canHaveMaxCategoriesSetting = (series, settings) => {
+  return Boolean(series && areAllBars(series, settings) && series.length >= 2);
+};
+
 export const GRAPH_DATA_SETTINGS = {
   ...columnSettings({
     getColumns: ([
@@ -96,12 +103,18 @@ export const GRAPH_DATA_SETTINGS = {
     getDefault: (series, vizSettings) =>
       getDefaultDimensions(series, vizSettings),
     persistDefault: true,
-    getProps: ([{ card, data }], vizSettings) => {
+    getProps: ([{ card, data }], vizSettings, _, { transformedSeries }) => {
       const addedDimensions = vizSettings["graph.dimensions"];
       const maxDimensionsSupported = getMaxDimensionsSupported(card.display);
       const options = data.cols
         .filter(getDefaultDimensionFilter(card.display))
         .map(getOptionFromColumn);
+      const fieldSettingWidgets = canHaveMaxCategoriesSetting(
+        transformedSeries,
+        vizSettings,
+      )
+        ? [null, "graph.max_categories"] // We want to show "graph.max_categories" setting for the breakout dimension (2nd)
+        : [];
       return {
         options,
         addAnother:
@@ -114,9 +127,7 @@ export const GRAPH_DATA_SETTINGS = {
             ? t`Add series breakout`
             : null,
         columns: data.cols,
-        // When this prop is passed it will only show the
-        // column settings for any index that is included in the array
-        showColumnSettingForIndicies: [0],
+        fieldSettingWidgets,
       };
     },
     writeDependencies: ["graph.metrics"],
@@ -134,18 +145,45 @@ export const GRAPH_DATA_SETTINGS = {
     section: t`Data`,
     widget: ChartSettingSeriesOrder,
     marginBottom: "1rem",
-
-    getValue: (series, settings) => {
-      const seriesKeys = series.map(s => keyForSingleSeries(s));
+    useRawSeries: true,
+    getValue: (rawSeries, settings) => {
+      const seriesModels = getSeriesModelsForSettings(rawSeries, settings);
+      const seriesKeys = seriesModels.map(s => s.vizSettingsKey);
       return getSeriesOrderVisibilitySettings(settings, seriesKeys);
     },
-    getHidden: (series, settings) => {
+    getProps: (rawSeries, settings, _onChange, _extra, onChangeSettings) => {
+      const groupedAfterIndex =
+        settings["graph.max_categories_enabled"] &&
+        settings["graph.max_categories"] !== 0
+          ? settings["graph.max_categories"]
+          : Infinity;
+      const onOtherColorChange = color =>
+        onChangeSettings({ "graph.other_category_color": color });
+      return {
+        rawSeries,
+        settings,
+        groupedAfterIndex,
+        otherColor: settings["graph.other_category_color"],
+        otherSettingWidgetId: "graph.max_categories",
+        onOtherColorChange,
+        truncateAfter: 10,
+      };
+    },
+    getHidden: (series, settings, { transformedSeries }) => {
       return (
-        settings["graph.dimensions"]?.length < 2 || series.length > MAX_SERIES
+        settings["graph.dimensions"]?.length < 2 ||
+        transformedSeries.length > MAX_SERIES
       );
     },
     dashboard: false,
-    readDependencies: ["series_settings.colors", "series_settings"],
+    readDependencies: [
+      "series_settings.colors",
+      "series_settings",
+      "graph.metrics",
+      "graph.dimensions",
+      "graph.max_categories",
+      "graph.other_category_color",
+    ],
     writeDependencies: ["graph.series_order_dimension"],
   },
   "graph.metrics": {
@@ -421,6 +459,45 @@ export const GRAPH_DISPLAY_VALUES_SETTINGS = {
     },
     default: getDefaultDataLabelsFormatting(),
   },
+  "graph.max_categories_enabled": {
+    hidden: true,
+    getDefault: () => false,
+    isValid: (series, settings) => {
+      return canHaveMaxCategoriesSetting(series, settings);
+    },
+    readDependencies: ["series_settings"],
+  },
+  "graph.max_categories": {
+    widget: ChartSettingMaxCategories,
+    hidden: true,
+    default: 8,
+    isValid: (series, settings) => {
+      return canHaveMaxCategoriesSetting(series, settings);
+    },
+    getProps: ([{ card }], settings) => {
+      return {
+        isEnabled: settings["graph.max_categories_enabled"],
+        aggregationFunction: settings["graph.other_category_aggregation_fn"],
+      };
+    },
+    readDependencies: [
+      "graph.max_categories_enabled",
+      "graph.other_category_aggregation_fn",
+      "series_settings",
+    ],
+  },
+  "graph.other_category_color": {
+    default: color("text-light"),
+  },
+  "graph.other_category_aggregation_fn": {
+    hidden: true,
+    getDefault: ([{ data }], settings) => {
+      const [metricName] = settings["graph.metrics"];
+      const metric = data.cols.find(col => col.name === metricName);
+      return metric?.aggregation_type ?? "sum";
+    },
+    readDependencies: ["graph.metrics"],
+  },
 };
 
 export const GRAPH_COLORS_SETTINGS = {
diff --git a/frontend/src/metabase/visualizations/lib/settings/series.js b/frontend/src/metabase/visualizations/lib/settings/series.js
index ad5c829106f..41bae587d64 100644
--- a/frontend/src/metabase/visualizations/lib/settings/series.js
+++ b/frontend/src/metabase/visualizations/lib/settings/series.js
@@ -2,6 +2,7 @@ import { getIn } from "icepick";
 import { t } from "ttag";
 
 import ChartNestedSettingSeries from "metabase/visualizations/components/settings/ChartNestedSettingSeries";
+import { OTHER_DATA_KEY } from "metabase/visualizations/echarts/cartesian/constants/dataset";
 import {
   SERIES_COLORS_SETTING_KEY,
   SERIES_SETTING_KEY,
@@ -59,6 +60,10 @@ export function seriesSetting({ readDependencies = [], def } = {}) {
       },
 
       getDefault: (single, settings, { series }) => {
+        if (keyForSingleSeries(single) === OTHER_DATA_KEY) {
+          return "bar"; // "other" series is always a bar chart now
+        }
+
         // FIXME: will move to Cartesian series model further, but now this code is used by other legacy charts
         const transformedSeriesIndex = series.findIndex(
           s => keyForSingleSeries(s) === keyForSingleSeries(single),
diff --git a/frontend/src/metabase/visualizations/shared/settings/cartesian-chart.ts b/frontend/src/metabase/visualizations/shared/settings/cartesian-chart.ts
index 3df9e4d8c73..6c96c496f60 100644
--- a/frontend/src/metabase/visualizations/shared/settings/cartesian-chart.ts
+++ b/frontend/src/metabase/visualizations/shared/settings/cartesian-chart.ts
@@ -7,6 +7,7 @@ import {
   getMaxMetricsSupported,
 } from "metabase/visualizations";
 import { getCardsColumns } from "metabase/visualizations/echarts/cartesian/model";
+import { getCardsSeriesModels } from "metabase/visualizations/echarts/cartesian/model/series";
 import { dimensionIsNumeric } from "metabase/visualizations/lib/numeric";
 import { dimensionIsTimeseries } from "metabase/visualizations/lib/timeseries";
 import {
@@ -437,3 +438,11 @@ export function getComputedAdditionalColumnsValue(
 
   return filteredStoredColumns;
 }
+
+export function getSeriesModelsForSettings(
+  rawSeries: RawSeries,
+  settings: ComputedVisualizationSettings,
+) {
+  const cardsColumns = getCardsColumns(rawSeries, settings);
+  return getCardsSeriesModels(rawSeries, cardsColumns, [], settings);
+}
diff --git a/frontend/src/metabase/visualizations/visualizations/CartesianChart/events.ts b/frontend/src/metabase/visualizations/visualizations/CartesianChart/events.ts
index 9464fe3e307..d42b983e86c 100644
--- a/frontend/src/metabase/visualizations/visualizations/CartesianChart/events.ts
+++ b/frontend/src/metabase/visualizations/visualizations/CartesianChart/events.ts
@@ -22,6 +22,7 @@ import {
 import { formatValueForTooltip } from "metabase/visualizations/components/ChartTooltip/utils";
 import {
   ORIGINAL_INDEX_DATA_KEY,
+  OTHER_DATA_KEY,
   X_AXIS_DATA_KEY,
 } from "metabase/visualizations/echarts/cartesian/constants/dataset";
 import {
@@ -29,8 +30,10 @@ import {
   isQuarterInterval,
   isTimeSeriesAxis,
 } from "metabase/visualizations/echarts/cartesian/model/guards";
+import { getOtherSeriesAggregationLabel } from "metabase/visualizations/echarts/cartesian/model/other-series";
 import type {
   BaseCartesianChartModel,
+  BaseSeriesModel,
   ChartDataset,
   DataKey,
   Datum,
@@ -205,7 +208,7 @@ const getEventColumnsData = (
 
 const computeDiffWithPreviousPeriod = (
   chartModel: BaseCartesianChartModel,
-  seriesIndex: number,
+  seriesModel: BaseSeriesModel,
   dataIndex: number,
 ): string | null => {
   if (!isTimeSeriesAxis(chartModel.xAxisModel)) {
@@ -213,7 +216,6 @@ const computeDiffWithPreviousPeriod = (
   }
 
   const datum = chartModel.dataset[dataIndex];
-  const seriesModel = chartModel.seriesModels[seriesIndex];
 
   const currentValue = datum[seriesModel.dataKey];
   const currentDate = parseTimestamp(datum[X_AXIS_DATA_KEY]);
@@ -315,30 +317,6 @@ export const getSeriesHovered = (
   };
 };
 
-export const getSeriesHoverData = (
-  chartModel: BaseCartesianChartModel,
-  settings: ComputedVisualizationSettings,
-  echartsDataIndex: number,
-  seriesId: DataKey,
-) => {
-  const dataIndex = getDataIndex(
-    chartModel.transformedDataset,
-    echartsDataIndex,
-  );
-  const seriesIndex = findSeriesModelIndexById(chartModel, seriesId);
-
-  if (seriesIndex < 0 || dataIndex == null) {
-    return;
-  }
-
-  return {
-    settings,
-    isAlreadyScaled: true,
-    index: seriesIndex,
-    datumIndex: dataIndex,
-  };
-};
-
 const getAdditionalTooltipRowsData = (
   chartModel: BaseCartesianChartModel,
   settings: ComputedVisualizationSettings,
@@ -384,11 +362,21 @@ export const getTooltipModel = (
   if (dataIndex == null) {
     return null;
   }
+
   const datum = chartModel.dataset[dataIndex];
-  const seriesIndex = chartModel.seriesModels.findIndex(
-    seriesModel => seriesModel.dataKey === seriesDataKey,
+
+  if (seriesDataKey === OTHER_DATA_KEY) {
+    return getOtherSeriesTooltipModel(chartModel, settings, dataIndex, datum);
+  }
+
+  const hoveredSeries = chartModel.seriesModels.find(
+    s => s.dataKey === seriesDataKey,
   );
-  const hoveredSeries = chartModel.seriesModels[seriesIndex];
+
+  if (!hoveredSeries) {
+    return null;
+  }
+
   const seriesStack = chartModel.stackModels.find(stackModel =>
     stackModel.seriesKeys.includes(hoveredSeries.dataKey),
   );
@@ -416,7 +404,6 @@ export const getTooltipModel = (
       hoveredSeries,
     );
   }
-
   return getSeriesOnlyTooltipModel(
     chartModel,
     settings,
@@ -490,15 +477,19 @@ export const getSeriesOnlyTooltipModel = (
 
   const seriesRows: EChartsTooltipRow[] = chartModel.seriesModels
     .filter(seriesModel => seriesModel.visible)
-    .map((seriesModel, seriesIndex) => {
+    .map(seriesModel => {
       const isHoveredSeries = seriesModel.dataKey === hoveredSeries.dataKey;
       const isFocused = isHoveredSeries && chartModel.seriesModels.length > 1;
 
-      const prevValue = computeDiffWithPreviousPeriod(
-        chartModel,
-        seriesIndex,
-        dataIndex,
-      );
+      const value =
+        seriesModel.dataKey === OTHER_DATA_KEY
+          ? chartModel.transformedDataset[dataIndex][OTHER_DATA_KEY]
+          : datum[seriesModel.dataKey];
+
+      const prevValue =
+        seriesModel.dataKey === OTHER_DATA_KEY
+          ? null
+          : computeDiffWithPreviousPeriod(chartModel, seriesModel, dataIndex);
 
       return {
         isFocused,
@@ -508,13 +499,13 @@ export const getSeriesOnlyTooltipModel = (
         ),
         values: [
           formatValueForTooltip({
-            value: datum[seriesModel.dataKey],
+            value: value,
             column: seriesModel.column,
             settings,
             isAlreadyScaled: true,
           }),
           prevValue,
-        ],
+        ].filter(isNotNull),
       };
     });
 
@@ -570,12 +561,18 @@ export const getStackedTooltipModel = (
         seriesStack?.seriesKeys.includes(seriesModel.dataKey),
     )
     .map(seriesModel => {
+      const datum = chartModel.dataset[dataIndex];
+      const value =
+        seriesModel.dataKey === OTHER_DATA_KEY
+          ? chartModel.transformedDataset[dataIndex][OTHER_DATA_KEY]
+          : datum[seriesModel.dataKey];
+
       return {
         isFocused: seriesModel.dataKey === seriesDataKey,
         name: seriesModel.name,
         color: seriesModel.color,
-        value: chartModel.dataset[dataIndex][seriesModel.dataKey],
         dataKey: seriesModel.dataKey,
+        value,
       };
     });
 
@@ -647,6 +644,74 @@ export const getStackedTooltipModel = (
   };
 };
 
+export const getOtherSeriesTooltipModel = (
+  chartModel: BaseCartesianChartModel,
+  settings: ComputedVisualizationSettings,
+  dataIndex: number,
+  datum: Datum,
+) => {
+  const { groupedSeriesModels = [] } = chartModel;
+
+  const rows = groupedSeriesModels
+    .map(seriesModel => ({
+      name: seriesModel.name,
+      column: seriesModel.column,
+      value: datum[seriesModel.dataKey],
+      prevValue: computeDiffWithPreviousPeriod(
+        chartModel,
+        seriesModel,
+        dataIndex,
+      ),
+    }))
+    .sort((a, b) => {
+      if (typeof a.value === "number" && typeof b.value === "number") {
+        return b.value - a.value;
+      }
+      return a.value === undefined ? 1 : -1;
+    })
+    .map(row => ({
+      name: row.name,
+      values: [
+        formatValueForTooltip({
+          value: row.value,
+          column: row.column,
+          isAlreadyScaled: true,
+          settings,
+        }),
+        row.prevValue,
+      ],
+    }));
+
+  rows.push({
+    name: getOtherSeriesAggregationLabel(
+      settings["graph.other_category_aggregation_fn"],
+    ),
+    values: [
+      String(
+        formatValueForTooltip({
+          isAlreadyScaled: true,
+          value: chartModel.transformedDataset[dataIndex][OTHER_DATA_KEY],
+          settings,
+          column:
+            chartModel.leftAxisModel?.column ??
+            chartModel.rightAxisModel?.column,
+        }),
+      ),
+    ],
+  });
+
+  return {
+    header: String(
+      formatValueForTooltip({
+        value: datum[X_AXIS_DATA_KEY],
+        column: chartModel.dimensionModel.column,
+        settings,
+      }),
+    ),
+    rows,
+  };
+};
+
 export const getTimelineEventsForEvent = (
   timelineEventsModel: TimelineEventsModel,
   event: EChartsSeriesMouseEvent,
@@ -720,7 +785,11 @@ export const getSeriesClickData = (
   const seriesIndex = findSeriesModelIndexById(chartModel, seriesId);
   const seriesModel = chartModel.seriesModels[seriesIndex];
 
-  if (seriesIndex < 0 || dataIndex == null) {
+  if (
+    seriesIndex < 0 ||
+    dataIndex == null ||
+    seriesModel?.dataKey === OTHER_DATA_KEY
+  ) {
     return;
   }
 
-- 
GitLab