diff --git a/docs/data/charts/scatter/ColorScaleNoSnap.js b/docs/data/charts/scatter/ColorScaleNoSnap.js
index ea446b982627..ce3243883cf2 100644
--- a/docs/data/charts/scatter/ColorScaleNoSnap.js
+++ b/docs/data/charts/scatter/ColorScaleNoSnap.js
@@ -9,11 +9,13 @@ import HighlightedCode from 'docs/src/modules/components/HighlightedCode';
import { Chance } from 'chance';
+const POINTS_NUMBER = 50;
const chance = new Chance(42);
export default function ColorScaleNoSnap() {
const [colorX, setColorX] = React.useState('piecewise');
const [colorY, setColorY] = React.useState('None');
+ const [colorZ, setColorZ] = React.useState('None');
return (
@@ -40,6 +42,18 @@ export default function ColorScaleNoSnap() {
+ setColorZ(event.target.value)}
+ >
+
+
+
+
+
'A'),
+ ...[...Array(POINTS_NUMBER)].map(() => 'B'),
+ ...[...Array(POINTS_NUMBER)].map(() => 'C'),
+ ...[...Array(POINTS_NUMBER)].map(() => 'D'),
+ ]
+ : undefined,
+ colorMap:
+ (colorZ === 'continuous' && {
+ type: 'continuous',
+ min: -2,
+ max: 2,
+ color: ['green', 'orange'],
+ }) ||
+ (colorZ === 'piecewise' && {
+ type: 'piecewise',
+ thresholds: [-1.5, 0, 1.5],
+ colors: ['#d01c8b', '#f1b6da', '#b8e186', '#4dac26'],
+ }) ||
+ (colorZ === 'ordinal' && {
+ type: 'ordinal',
+ values: ['A', 'B', 'C', 'D'],
+ colors: ['#d01c8b', '#f1b6da', '#b8e186', '#4dac26'],
+ }) ||
+ undefined,
+ },
+ ]}
/>
({
+const series = [
+ {
+ data: [
+ ...getGaussianSeriesData([-1, -1]),
+ ...getGaussianSeriesData([-1, 1]),
+ ...getGaussianSeriesData([1, 1]),
+ ...getGaussianSeriesData([1, -1]),
+ ],
+ },
+].map((s) => ({
...s,
valueFormatter: (v) => `(${v.x.toFixed(1)}, ${v.y.toFixed(1)})`,
}));
-function getGaussianSeriesData(mean, stdev = [0.3, 0.4], N = 50) {
+function getGaussianSeriesData(mean, stdev = [0.5, 0.5], N = 50) {
return [...Array(N)].map((_, i) => {
const x =
Math.sqrt(-2.0 * Math.log(1 - chance.floating({ min: 0, max: 0.99 }))) *
@@ -167,6 +221,6 @@ function getGaussianSeriesData(mean, stdev = [0.3, 0.4], N = 50) {
Math.cos(2.0 * Math.PI * chance.floating({ min: 0, max: 0.99 })) *
stdev[1] +
mean[1];
- return { x, y, id: i };
+ return { x, y, z: x + y, id: i };
});
}
diff --git a/docs/data/charts/scatter/ColorScaleNoSnap.tsx b/docs/data/charts/scatter/ColorScaleNoSnap.tsx
index 3ab5d985ef84..1f3f10234449 100644
--- a/docs/data/charts/scatter/ColorScaleNoSnap.tsx
+++ b/docs/data/charts/scatter/ColorScaleNoSnap.tsx
@@ -9,6 +9,7 @@ import HighlightedCode from 'docs/src/modules/components/HighlightedCode';
import { Chance } from 'chance';
+const POINTS_NUMBER = 50;
const chance = new Chance(42);
export default function ColorScaleNoSnap() {
@@ -18,6 +19,9 @@ export default function ColorScaleNoSnap() {
const [colorY, setColorY] = React.useState<'None' | 'piecewise' | 'continuous'>(
'None',
);
+ const [colorZ, setColorZ] = React.useState<
+ 'None' | 'piecewise' | 'continuous' | 'ordinal'
+ >('None');
return (
@@ -48,6 +52,22 @@ export default function ColorScaleNoSnap() {
+
+ setColorZ(
+ event.target.value as 'None' | 'piecewise' | 'continuous' | 'ordinal',
+ )
+ }
+ >
+
+
+
+
+
'A'),
+ ...[...Array(POINTS_NUMBER)].map(() => 'B'),
+ ...[...Array(POINTS_NUMBER)].map(() => 'C'),
+ ...[...Array(POINTS_NUMBER)].map(() => 'D'),
+ ]
+ : undefined,
+ colorMap:
+ (colorZ === 'continuous' && {
+ type: 'continuous',
+ min: -2,
+ max: 2,
+ color: ['green', 'orange'],
+ }) ||
+ (colorZ === 'piecewise' && {
+ type: 'piecewise',
+ thresholds: [-1.5, 0, 1.5],
+ colors: ['#d01c8b', '#f1b6da', '#b8e186', '#4dac26'],
+ }) ||
+ (colorZ === 'ordinal' && {
+ type: 'ordinal',
+
+ values: ['A', 'B', 'C', 'D'],
+ colors: ['#d01c8b', '#f1b6da', '#b8e186', '#4dac26'],
+ }) ||
+ undefined,
+ },
+ ]}
/>
({
+const series = [
+ {
+ data: [
+ ...getGaussianSeriesData([-1, -1]),
+ ...getGaussianSeriesData([-1, 1]),
+ ...getGaussianSeriesData([1, 1]),
+ ...getGaussianSeriesData([1, -1]),
+ ],
+ },
+].map((s) => ({
...s,
valueFormatter: (v: ScatterValueType) => `(${v.x.toFixed(1)}, ${v.y.toFixed(1)})`,
}));
function getGaussianSeriesData(
mean: [number, number],
- stdev: [number, number] = [0.3, 0.4],
+ stdev: [number, number] = [0.5, 0.5],
N: number = 50,
) {
return [...Array(N)].map((_, i) => {
@@ -180,6 +241,6 @@ function getGaussianSeriesData(
Math.cos(2.0 * Math.PI * chance.floating({ min: 0, max: 0.99 })) *
stdev[1] +
mean[1];
- return { x, y, id: i };
+ return { x, y, z: x + y, id: i };
});
}
diff --git a/docs/data/charts/scatter/scatter.md b/docs/data/charts/scatter/scatter.md
index 89dbca75e8a1..1ebeebf8ec9f 100644
--- a/docs/data/charts/scatter/scatter.md
+++ b/docs/data/charts/scatter/scatter.md
@@ -60,9 +60,31 @@ As with other charts, you can modify the [series color](/x/react-charts/styling/
You can also modify the color by using axes `colorMap` which maps values to colors.
The scatter charts use by priority:
-1. The y-axis color
-2. The x-axis color
-3. The series color
+1. The z-axis color
+2. The y-axis color
+3. The x-axis color
+4. The series color
+
+:::info
+The z-axis is a third axis that allows to customize scatter points independently from their position.
+It can be provided with `zAxis` props, or with `ZAxisContextProvider` when using composition.
+
+The value to map can either come from the `z` property of series data, or from the zAxis data.
+Here are three ways to set z value to 5.
+
+```jsx
+
+```
+
+:::
Learn more about the `colorMap` properties in the [Styling docs](/x/react-charts/styling/#values-color).
diff --git a/docs/pages/x/api/charts/scatter-chart.json b/docs/pages/x/api/charts/scatter-chart.json
index b0314f723843..c2e6985c1e8c 100644
--- a/docs/pages/x/api/charts/scatter-chart.json
+++ b/docs/pages/x/api/charts/scatter-chart.json
@@ -95,6 +95,12 @@
"name": "arrayOf",
"description": "Array<{ axisId?: number
| string, classes?: object, colorMap?: { color: Array<string>
| func, max?: Date
| number, min?: Date
| number, type: 'continuous' }
| { colors: Array<string>, thresholds: Array<Date
| number>, type: 'piecewise' }
| { colors: Array<string>, type: 'ordinal', unknownColor?: string, values?: Array<Date
| number
| string> }, data?: array, dataKey?: string, disableLine?: bool, disableTicks?: bool, fill?: string, hideTooltip?: bool, id?: number
| string, label?: string, labelFontSize?: number, labelStyle?: object, max?: Date
| number, min?: Date
| number, position?: 'bottom'
| 'left'
| 'right'
| 'top', reverse?: bool, scaleType?: 'band'
| 'linear'
| 'log'
| 'point'
| 'pow'
| 'sqrt'
| 'time'
| 'utc', slotProps?: object, slots?: object, stroke?: string, tickFontSize?: number, tickInterval?: 'auto'
| array
| func, tickLabelInterval?: 'auto'
| func, tickLabelPlacement?: 'middle'
| 'tick', tickLabelStyle?: object, tickMaxStep?: number, tickMinStep?: number, tickNumber?: number, tickPlacement?: 'end'
| 'extremities'
| 'middle'
| 'start', tickSize?: number, valueFormatter?: func }>"
}
+ },
+ "zAxis": {
+ "type": {
+ "name": "arrayOf",
+ "description": "Array<{ colorMap?: { color: Array<string>
| func, max?: Date
| number, min?: Date
| number, type: 'continuous' }
| { colors: Array<string>, thresholds: Array<Date
| number>, type: 'piecewise' }
| { colors: Array<string>, type: 'ordinal', unknownColor?: string, values?: Array<Date
| number
| string> }, data?: array, dataKey?: string, id?: string }>"
+ }
}
},
"name": "ScatterChart",
diff --git a/docs/translations/api-docs/charts/scatter-chart/scatter-chart.json b/docs/translations/api-docs/charts/scatter-chart/scatter-chart.json
index ad851d29ce89..1f59c3309dae 100644
--- a/docs/translations/api-docs/charts/scatter-chart/scatter-chart.json
+++ b/docs/translations/api-docs/charts/scatter-chart/scatter-chart.json
@@ -59,6 +59,9 @@
},
"yAxis": {
"description": "The configuration of the y-axes. If not provided, a default axis config is used."
+ },
+ "zAxis": {
+ "description": "The configuration of the x-axes. If not provided, a default axis config is used with id set to DEFAULT_X_AXIS_KEY
."
}
},
"classDescriptions": {},
diff --git a/packages/x-charts/src/context/index.ts b/packages/x-charts/src/context/index.ts
index 58cbd7715d35..bdf832550c5c 100644
--- a/packages/x-charts/src/context/index.ts
+++ b/packages/x-charts/src/context/index.ts
@@ -1 +1,2 @@
export type { HighlightOptions, FadeOptions, HighlightScope } from './HighlightProvider';
+export { ZAxisContextProvider, ZAxisContextProviderProps } from './ZAxisContextProvider';
diff --git a/packages/x-charts/src/models/colorMapping.ts b/packages/x-charts/src/models/colorMapping.ts
index 045de15faa73..ba5dd13ecd5a 100644
--- a/packages/x-charts/src/models/colorMapping.ts
+++ b/packages/x-charts/src/models/colorMapping.ts
@@ -11,7 +11,7 @@ export interface ContinuousColorConfig {
*/
max?: Value;
/**
- * The colors to render. Can either be and array with the extrem colors, or an interpolation function.
+ * The colors to render. It can be an array with the extremum colors, or an interpolation function.
*/
color: [string, string] | ((t: number) => string);
}
@@ -24,7 +24,7 @@ export interface PiecewiseColorConfig {
thresholds: Value[];
/**
* The colors used for each band defined by `thresholds`.
- * Should contain N+1 colors with N the number of thresholds.
+ * Should contain N+1 colors, where N is the number of thresholds.
*/
colors: string[];
}
@@ -38,6 +38,7 @@ export interface OrdinalColorConfig {
values?: Value[];
/**
* The color palette.
+ * Items equal to `values[k]` will get the color of `colors[k]`.
*/
colors: string[];
/**
diff --git a/scripts/x-charts.exports.json b/scripts/x-charts.exports.json
index a58bf1eee63c..8e34fbddc6b8 100644
--- a/scripts/x-charts.exports.json
+++ b/scripts/x-charts.exports.json
@@ -267,5 +267,7 @@
{ "name": "useGaugeState", "kind": "Function" },
{ "name": "useSvgRef", "kind": "Function" },
{ "name": "useXScale", "kind": "Function" },
- { "name": "useYScale", "kind": "Function" }
+ { "name": "useYScale", "kind": "Function" },
+ { "name": "ZAxisContextProvider", "kind": "Function" },
+ { "name": "ZAxisContextProviderProps", "kind": "TypeAlias" }
]