diff --git a/docs/data/charts/scatter/ScatterDataset.js b/docs/data/charts/scatter/ScatterDataset.js
new file mode 100644
index 0000000000000..5a50fdc796762
--- /dev/null
+++ b/docs/data/charts/scatter/ScatterDataset.js
@@ -0,0 +1,104 @@
+import * as React from 'react';
+import { ScatterChart } from '@mui/x-charts/ScatterChart';
+import { axisClasses } from '@mui/x-charts/ChartsAxis';
+
+const dataset = [
+ {
+ version: 'data-0',
+ a1: 329.39,
+ a2: 391.29,
+ b1: 443.28,
+ b2: 153.9,
+ },
+ {
+ version: 'data-1',
+ a1: 96.94,
+ a2: 139.6,
+ b1: 110.5,
+ b2: 217.8,
+ },
+ {
+ version: 'data-2',
+ a1: 336.35,
+ a2: 282.34,
+ b1: 175.23,
+ b2: 286.32,
+ },
+ {
+ version: 'data-3',
+ a1: 159.44,
+ a2: 384.85,
+ b1: 195.97,
+ b2: 325.12,
+ },
+ {
+ version: 'data-4',
+ a1: 188.86,
+ a2: 182.27,
+ b1: 351.77,
+ b2: 144.58,
+ },
+ {
+ version: 'data-5',
+ a1: 143.86,
+ a2: 360.22,
+ b1: 43.253,
+ b2: 146.51,
+ },
+ {
+ version: 'data-6',
+ a1: 202.02,
+ a2: 209.5,
+ b1: 376.34,
+ b2: 309.69,
+ },
+ {
+ version: 'data-7',
+ a1: 384.41,
+ a2: 258.93,
+ b1: 31.514,
+ b2: 236.38,
+ },
+ {
+ version: 'data-8',
+ a1: 256.76,
+ a2: 70.571,
+ b1: 231.31,
+ b2: 440.72,
+ },
+ {
+ version: 'data-9',
+ a1: 143.79,
+ a2: 419.02,
+ b1: 108.04,
+ b2: 20.29,
+ },
+];
+
+const chartSetting = {
+ yAxis: [
+ {
+ label: 'rainfall (mm)',
+ },
+ ],
+ sx: {
+ [`.${axisClasses.left} .${axisClasses.label}`]: {
+ transform: 'translate(-20px, 0)',
+ },
+ },
+ width: 500,
+ height: 300,
+};
+
+export default function ScatterDataset() {
+ return (
+
+ );
+}
diff --git a/docs/data/charts/scatter/ScatterDataset.tsx b/docs/data/charts/scatter/ScatterDataset.tsx
new file mode 100644
index 0000000000000..5a50fdc796762
--- /dev/null
+++ b/docs/data/charts/scatter/ScatterDataset.tsx
@@ -0,0 +1,104 @@
+import * as React from 'react';
+import { ScatterChart } from '@mui/x-charts/ScatterChart';
+import { axisClasses } from '@mui/x-charts/ChartsAxis';
+
+const dataset = [
+ {
+ version: 'data-0',
+ a1: 329.39,
+ a2: 391.29,
+ b1: 443.28,
+ b2: 153.9,
+ },
+ {
+ version: 'data-1',
+ a1: 96.94,
+ a2: 139.6,
+ b1: 110.5,
+ b2: 217.8,
+ },
+ {
+ version: 'data-2',
+ a1: 336.35,
+ a2: 282.34,
+ b1: 175.23,
+ b2: 286.32,
+ },
+ {
+ version: 'data-3',
+ a1: 159.44,
+ a2: 384.85,
+ b1: 195.97,
+ b2: 325.12,
+ },
+ {
+ version: 'data-4',
+ a1: 188.86,
+ a2: 182.27,
+ b1: 351.77,
+ b2: 144.58,
+ },
+ {
+ version: 'data-5',
+ a1: 143.86,
+ a2: 360.22,
+ b1: 43.253,
+ b2: 146.51,
+ },
+ {
+ version: 'data-6',
+ a1: 202.02,
+ a2: 209.5,
+ b1: 376.34,
+ b2: 309.69,
+ },
+ {
+ version: 'data-7',
+ a1: 384.41,
+ a2: 258.93,
+ b1: 31.514,
+ b2: 236.38,
+ },
+ {
+ version: 'data-8',
+ a1: 256.76,
+ a2: 70.571,
+ b1: 231.31,
+ b2: 440.72,
+ },
+ {
+ version: 'data-9',
+ a1: 143.79,
+ a2: 419.02,
+ b1: 108.04,
+ b2: 20.29,
+ },
+];
+
+const chartSetting = {
+ yAxis: [
+ {
+ label: 'rainfall (mm)',
+ },
+ ],
+ sx: {
+ [`.${axisClasses.left} .${axisClasses.label}`]: {
+ transform: 'translate(-20px, 0)',
+ },
+ },
+ width: 500,
+ height: 300,
+};
+
+export default function ScatterDataset() {
+ return (
+
+ );
+}
diff --git a/docs/data/charts/scatter/ScatterDataset.tsx.preview b/docs/data/charts/scatter/ScatterDataset.tsx.preview
new file mode 100644
index 0000000000000..41a49c4bd1578
--- /dev/null
+++ b/docs/data/charts/scatter/ScatterDataset.tsx.preview
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/docs/data/charts/scatter/scatter.md b/docs/data/charts/scatter/scatter.md
index 967e8eabbf383..0422d0c528589 100644
--- a/docs/data/charts/scatter/scatter.md
+++ b/docs/data/charts/scatter/scatter.md
@@ -15,6 +15,18 @@ Those objects require `x`, `y`, and `id` properties.
{{"demo": "BasicScatter.js"}}
+### Using a dataset
+
+If your data is stored in an array of objects, you can use the `dataset` helper prop.
+It accepts an array of objects such as `dataset={[{a: 1, b: 32, c: 873}, {a: 2, b: 41, c: 182}, ...]}`.
+
+You can reuse this data when defining the series.
+The scatter series work a bit differently than in other charts.
+You need to specify the `datasetKeys` properties which is an object that requires `x`, `y`, and `id` keys.
+With an optional `z` key if needed.
+
+{{"demo": "ScatterDataset.js"}}
+
## Interaction
Since scatter elements can be small, interactions do not require hovering exactly over an element.
diff --git a/docs/next-env.d.ts b/docs/next-env.d.ts
index 4f11a03dc6cc3..a4a7b3f5cfa2f 100644
--- a/docs/next-env.d.ts
+++ b/docs/next-env.d.ts
@@ -2,4 +2,4 @@
///
// NOTE: This file should not be edited
-// see https://nextjs.org/docs/basic-features/typescript for more information.
+// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information.
diff --git a/docs/pages/x/api/charts/scatter-series-type.json b/docs/pages/x/api/charts/scatter-series-type.json
index 7488c7cc1a370..9d560abcee2dd 100644
--- a/docs/pages/x/api/charts/scatter-series-type.json
+++ b/docs/pages/x/api/charts/scatter-series-type.json
@@ -2,9 +2,14 @@
"name": "ScatterSeriesType",
"imports": ["import { ScatterSeriesType } from '@mui/x-charts'"],
"properties": {
- "data": { "type": { "description": "ScatterValueType[]" }, "required": true },
"type": { "type": { "description": "'scatter'" }, "required": true },
"color": { "type": { "description": "string" } },
+ "data": { "type": { "description": "ScatterValueType[]" } },
+ "datasetKeys": {
+ "type": {
+ "description": "{
/**
* The key used to retrieve data from the dataset for the X axis.
*/
x: string
/**
* The key used to retrieve data from the dataset for the Y axis.
*/
y: string
/**
* The key used to retrieve data from the dataset for the Z axis.
*/
z?: string
/**
* The key used to retrieve data from the dataset for the id.
*/
id: string
}"
+ }
+ },
"disableHover": { "type": { "description": "boolean" }, "default": "false" },
"highlightScope": { "type": { "description": "Partial<HighlightScope>" } },
"id": { "type": { "description": "SeriesId" } },
diff --git a/docs/translations/api-docs/charts/scatter-series-type.json b/docs/translations/api-docs/charts/scatter-series-type.json
index f2c801b5c89d4..4f3fed0aa9e92 100644
--- a/docs/translations/api-docs/charts/scatter-series-type.json
+++ b/docs/translations/api-docs/charts/scatter-series-type.json
@@ -1,9 +1,12 @@
{
"interfaceDescription": "",
"propertiesDescriptions": {
- "data": { "description": "" },
"type": { "description": "" },
"color": { "description": "" },
+ "data": { "description": "" },
+ "datasetKeys": {
+ "description": "The keys used to retrieve data from the dataset.
When this prop is provided, all of x
, y
, and id
must be provided.
While z
is optional."
+ },
"disableHover": {
"description": "If true, the interaction will not use element hover for this series."
},
diff --git a/packages/x-charts/src/ScatterChart/extremums.ts b/packages/x-charts/src/ScatterChart/extremums.ts
index 77fcd28946bee..806295a1997ff 100644
--- a/packages/x-charts/src/ScatterChart/extremums.ts
+++ b/packages/x-charts/src/ScatterChart/extremums.ts
@@ -27,7 +27,7 @@ export const getExtremumX: ExtremumGetter<'scatter'> = (params) => {
seriesYAxisId: series[seriesId].yAxisId ?? series[seriesId].yAxisKey,
});
- const seriesMinMax = series[seriesId].data.reduce(
+ const seriesMinMax = series[seriesId].data?.reduce(
(accSeries, d, dataIndex) => {
if (filter && !filter(d, dataIndex)) {
return accSeries;
@@ -36,7 +36,7 @@ export const getExtremumX: ExtremumGetter<'scatter'> = (params) => {
},
[Infinity, -Infinity],
);
- return mergeMinMax(acc, seriesMinMax);
+ return mergeMinMax(acc, seriesMinMax ?? [Infinity, -Infinity]);
},
[Infinity, -Infinity],
);
@@ -59,7 +59,7 @@ export const getExtremumY: ExtremumGetter<'scatter'> = (params) => {
seriesYAxisId: series[seriesId].yAxisId ?? series[seriesId].yAxisKey,
});
- const seriesMinMax = series[seriesId].data.reduce(
+ const seriesMinMax = series[seriesId].data?.reduce(
(accSeries, d, dataIndex) => {
if (filter && !filter(d, dataIndex)) {
return accSeries;
@@ -68,7 +68,7 @@ export const getExtremumY: ExtremumGetter<'scatter'> = (params) => {
},
[Infinity, -Infinity],
);
- return mergeMinMax(acc, seriesMinMax);
+ return mergeMinMax(acc, seriesMinMax ?? [Infinity, -Infinity]);
},
[Infinity, -Infinity],
);
diff --git a/packages/x-charts/src/ScatterChart/formatter.ts b/packages/x-charts/src/ScatterChart/formatter.ts
index 671b8fc4353dc..60c024f88c2e4 100644
--- a/packages/x-charts/src/ScatterChart/formatter.ts
+++ b/packages/x-charts/src/ScatterChart/formatter.ts
@@ -1,9 +1,48 @@
-import { defaultizeValueFormatter } from '../internals/defaultizeValueFormatter';
import { SeriesFormatter } from '../context/PluginProvider/SeriesFormatter.types';
+import { ScatterValueType } from '../models';
+
+const formatter: SeriesFormatter<'scatter'> = ({ series, seriesOrder }, dataset) => {
+ const completeSeries = Object.fromEntries(
+ Object.entries(series).map(([seriesId, seriesData]) => {
+ const datasetKeys = seriesData?.datasetKeys;
+
+ const missingKeys = (['x', 'y', 'id'] as const).filter(
+ (key) => typeof datasetKeys?.[key] !== 'string',
+ );
+
+ if (seriesData?.datasetKeys && missingKeys.length > 0) {
+ throw new Error(
+ [
+ `MUI X: scatter series with id='${seriesId}' has incomplete datasetKeys.`,
+ `Properties ${missingKeys.map((key) => `"${key}"`).join(', ')} are missing.`,
+ ].join('\n'),
+ );
+ }
+
+ const data = !datasetKeys
+ ? (seriesData.data ?? [])
+ : (dataset?.map((d) => {
+ return {
+ x: d[datasetKeys.x],
+ y: d[datasetKeys.y],
+ z: datasetKeys.z && d[datasetKeys.z],
+ id: d[datasetKeys.id],
+ } as ScatterValueType;
+ }) ?? []);
+
+ return [
+ seriesId,
+ {
+ ...seriesData,
+ data,
+ valueFormatter: seriesData.valueFormatter ?? ((v) => `(${v.x}, ${v.y})`),
+ },
+ ];
+ }),
+ );
-const formatter: SeriesFormatter<'scatter'> = ({ series, seriesOrder }) => {
return {
- series: defaultizeValueFormatter(series, (v) => `(${v.x}, ${v.y})`),
+ series: completeSeries,
seriesOrder,
};
};
diff --git a/packages/x-charts/src/models/seriesType/scatter.ts b/packages/x-charts/src/models/seriesType/scatter.ts
index 4048b662c3889..211763f1ef36c 100644
--- a/packages/x-charts/src/models/seriesType/scatter.ts
+++ b/packages/x-charts/src/models/seriesType/scatter.ts
@@ -13,7 +13,7 @@ export type ScatterValueType = {
export interface ScatterSeriesType extends CommonSeriesType, CartesianSeriesType {
type: 'scatter';
- data: ScatterValueType[];
+ data?: ScatterValueType[];
markerSize?: number;
/**
* The label to display on the tooltip or the legend. It can be a string or a function.
@@ -33,6 +33,31 @@ export interface ScatterSeriesType extends CommonSeriesType, C
* The id of the z-axis used to render the series.
*/
zAxisId?: string;
+
+ /**
+ * The keys used to retrieve data from the dataset.
+ *
+ * When this prop is provided, all of `x`, `y`, and `id` must be provided.
+ * While `z` is optional.
+ */
+ datasetKeys?: {
+ /**
+ * The key used to retrieve data from the dataset for the X axis.
+ */
+ x: string;
+ /**
+ * The key used to retrieve data from the dataset for the Y axis.
+ */
+ y: string;
+ /**
+ * The key used to retrieve data from the dataset for the Z axis.
+ */
+ z?: string;
+ /**
+ * The key used to retrieve data from the dataset for the id.
+ */
+ id: string;
+ };
}
/**