Skip to content

Commit 2709bce

Browse files
committed
[charts] Support unknown color in colorscale
1 parent 6f7850a commit 2709bce

13 files changed

Lines changed: 227 additions & 52 deletions

File tree

docs/data/charts/map/ColorScaleMapShape.js

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import * as React from 'react';
2+
import { useTheme } from '@mui/material/styles';
23
import Box from '@mui/material/Box';
34
import Stack from '@mui/material/Stack';
45
import Typography from '@mui/material/Typography';
6+
import Checkbox from '@mui/material/Checkbox';
7+
import FormControlLabel from '@mui/material/FormControlLabel';
58
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
69
import ToggleButton from '@mui/material/ToggleButton';
710
import { interpolateBlues } from 'd3-scale-chromatic';
@@ -31,20 +34,35 @@ const data = Object.keys(countryData).map((code) => ({
3134

3235
export default function ColorScaleMapShape() {
3336
const [colorMap, setColorMap] = React.useState('continuous');
37+
const [unknownColor, setUnknownColor] = React.useState(true);
3438

39+
const theme = useTheme();
3540
return (
3641
<Stack spacing={2} sx={{ width: '100%', maxWidth: 800 }}>
37-
<ToggleButtonGroup
38-
color="primary"
39-
size="small"
40-
exclusive
41-
value={colorMap}
42-
onChange={(_, value) => value && setColorMap(value)}
43-
aria-label="color map"
42+
<Stack
43+
direction="row"
44+
sx={{ alignItems: 'center', justifyContent: 'space-between' }}
4445
>
45-
<ToggleButton value="continuous">continuous</ToggleButton>
46-
<ToggleButton value="piecewise">piecewise</ToggleButton>
47-
</ToggleButtonGroup>
46+
<ToggleButtonGroup
47+
color="primary"
48+
size="small"
49+
exclusive
50+
value={colorMap}
51+
onChange={(_, value) => value && setColorMap(value)}
52+
aria-label="color map"
53+
>
54+
<ToggleButton value="continuous">continuous</ToggleButton>
55+
<ToggleButton value="piecewise">piecewise</ToggleButton>
56+
</ToggleButtonGroup>
57+
<FormControlLabel
58+
checked={unknownColor}
59+
control={
60+
<Checkbox onChange={(event) => setUnknownColor(event.target.checked)} />
61+
}
62+
label="Use unknown color"
63+
labelPlacement="end"
64+
/>
65+
</Stack>
4866
<Typography variant="body2" component="h6" sx={{ textAlign: 'end' }}>
4967
Share of the population using the Internet in 2020
5068
</Typography>
@@ -74,11 +92,13 @@ export default function ColorScaleMapShape() {
7492
min: 0,
7593
max: 100,
7694
color: ['#e3f2fd', '#0d47a1'],
95+
unknownColor: unknownColor ? 'gray' : undefined,
7796
}
7897
: {
7998
type: 'piecewise',
8099
thresholds: [25, 50, 75],
81100
colors: [0.25, 0.5, 0.75, 1].map(interpolateBlues),
101+
unknownColor: unknownColor ? 'gray' : undefined,
82102
},
83103
},
84104
]}

docs/data/charts/map/ColorScaleMapShape.tsx

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import * as React from 'react';
2+
import { useTheme } from '@mui/material/styles';
23
import Box from '@mui/material/Box';
34
import Stack from '@mui/material/Stack';
45
import Typography from '@mui/material/Typography';
6+
import Checkbox from '@mui/material/Checkbox';
7+
import FormControlLabel from '@mui/material/FormControlLabel';
58
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
69
import ToggleButton from '@mui/material/ToggleButton';
710
import { interpolateBlues } from 'd3-scale-chromatic';
@@ -36,20 +39,35 @@ type ColorMapType = 'continuous' | 'piecewise';
3639

3740
export default function ColorScaleMapShape() {
3841
const [colorMap, setColorMap] = React.useState<ColorMapType>('continuous');
42+
const [unknownColor, setUnknownColor] = React.useState(true);
3943

44+
const theme = useTheme();
4045
return (
4146
<Stack spacing={2} sx={{ width: '100%', maxWidth: 800 }}>
42-
<ToggleButtonGroup
43-
color="primary"
44-
size="small"
45-
exclusive
46-
value={colorMap}
47-
onChange={(_, value: ColorMapType | null) => value && setColorMap(value)}
48-
aria-label="color map"
47+
<Stack
48+
direction="row"
49+
sx={{ alignItems: 'center', justifyContent: 'space-between' }}
4950
>
50-
<ToggleButton value="continuous">continuous</ToggleButton>
51-
<ToggleButton value="piecewise">piecewise</ToggleButton>
52-
</ToggleButtonGroup>
51+
<ToggleButtonGroup
52+
color="primary"
53+
size="small"
54+
exclusive
55+
value={colorMap}
56+
onChange={(_, value: ColorMapType | null) => value && setColorMap(value)}
57+
aria-label="color map"
58+
>
59+
<ToggleButton value="continuous">continuous</ToggleButton>
60+
<ToggleButton value="piecewise">piecewise</ToggleButton>
61+
</ToggleButtonGroup>
62+
<FormControlLabel
63+
checked={unknownColor}
64+
control={
65+
<Checkbox onChange={(event) => setUnknownColor(event.target.checked)} />
66+
}
67+
label="Use unknown color"
68+
labelPlacement="end"
69+
/>
70+
</Stack>
5371
<Typography variant="body2" component="h6" sx={{ textAlign: 'end' }}>
5472
Share of the population using the Internet in 2020
5573
</Typography>
@@ -79,11 +97,13 @@ export default function ColorScaleMapShape() {
7997
min: 0,
8098
max: 100,
8199
color: ['#e3f2fd', '#0d47a1'],
100+
unknownColor: unknownColor ? 'gray' : undefined,
82101
}
83102
: {
84103
type: 'piecewise',
85104
thresholds: [25, 50, 75],
86105
colors: [0.25, 0.5, 0.75, 1].map(interpolateBlues),
106+
unknownColor: unknownColor ? 'gray' : undefined,
87107
},
88108
},
89109
]}

docs/data/charts/map/map.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ When no `colorValue` is provided, the item's `value` is used as a fallback.
111111

112112
If several `zAxis` are defined, the series can target one explicitly with the `colorAxisId` property.
113113

114+
By default shapes with unknown values are ignored.
115+
Specify the `unknownColor` property in the `colorMap` to render them.
116+
114117
{{"demo": "ColorScaleMapShape.js"}}
115118

116119
## Using a dataset

docs/data/charts/styling/styling.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ See the dedicated documentation sections for each chart component to learn more
5050
- [Bar charts](/x/react-charts/bars/#color-scale)
5151
- [Line charts](/x/react-charts/lines/#color-scale)
5252
- [Bubble charts](/x/react-charts/bubble/#mapping-data-to-color)
53+
- [Maps](/x/react-charts/map/#mapping-values-to-colors)[<span class="plan-premium"></span>](/x/introduction/licensing/#premium-plan 'Premium plan')
5354

5455
The `colorMap` property accepts three kinds of objects for color maps: piecewise, continuous, and ordinal.
5556

@@ -62,6 +63,7 @@ You can configure a piecewise color map with an array of _n_ `thresholds` values
6263
type: 'piecewise';
6364
thresholds: Value[];
6465
colors: string[];
66+
unknownColor?: string;
6567
}
6668
```
6769

@@ -82,6 +84,7 @@ By default, the `min`-`max` range is 0-100.
8284
min?: Value;
8385
max?: Value;
8486
color: [string, string] | ((t: number) => string);
87+
unknownColor?: string;
8588
}
8689
```
8790

packages/x-charts-premium/src/BarChartPremium/RangeBar/seriesConfig/getColor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ const getColor: ColorProcessor<'rangeBar'> = (series, xAxis, yAxis) => {
1414
}
1515

1616
const value = bandValues[dataIndex];
17-
const color = value === null ? getSeriesColor({ value, dataIndex }) : bandColorScale(value);
17+
const color = bandColorScale(value);
1818

19-
if (color === null) {
19+
if (typeof color !== 'string') {
2020
return getSeriesColor({ value, dataIndex });
2121
}
2222

packages/x-charts-premium/src/Map/MapShapePlot.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ export function MapShapePlot(props: MapShapePlotProps) {
7373
{featureIndexes.map((featureIndex) => {
7474
const feature = geoData.features[featureIndex];
7575
const d = path(feature);
76-
if (!d) {
76+
const color = fill ?? colorGetter(dataIndex);
77+
if (!d || color === null) {
7778
return null;
7879
}
7980
return (
@@ -82,7 +83,7 @@ export function MapShapePlot(props: MapShapePlotProps) {
8283
seriesId={id}
8384
dataIndex={dataIndex}
8485
d={d}
85-
color={fill ?? colorGetter(dataIndex)}
86+
color={color}
8687
stroke={stroke}
8788
strokeWidth={strokeWidth}
8889
/>

packages/x-charts-premium/src/Map/seriesConfig/getColor.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,15 @@ const getColor: ColorProcessor<'mapShape'> = (series, _mainAxis, _secondaryAxis,
99
return series.color;
1010
}
1111
const item = series.data[dataIndex];
12-
if (item === undefined) {
13-
return series.color;
12+
13+
if (item.color !== undefined) {
14+
return item.color;
1415
}
1516
const scaleInput = item.colorValue ?? item.value;
16-
if (scaleInput != null) {
17-
const color = colorScale(scaleInput);
18-
if (color !== null) {
19-
return color;
20-
}
21-
}
22-
return item.color ?? series.color;
17+
18+
const color = colorScale(scaleInput);
19+
20+
return color;
2321
};
2422
}
2523

packages/x-charts/src/ScatterChart/seriesConfig/getColor.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,8 @@ const getColor: ColorProcessor<'scatter'> = (series, xAxis, yAxis, zAxis) => {
2020
}
2121
}
2222
const value = series.data[dataIndex];
23-
const color =
24-
value === null
25-
? getSeriesColor({ value, dataIndex })
26-
: zColorScale(value.colorValue ?? value.z);
27-
if (color === null) {
23+
const color = zColorScale(value.colorValue ?? value.z);
24+
if (typeof color !== 'string') {
2825
return getSeriesColor({ value, dataIndex });
2926
}
3027
return color;
@@ -37,8 +34,8 @@ const getColor: ColorProcessor<'scatter'> = (series, xAxis, yAxis, zAxis) => {
3734
return series.color;
3835
}
3936
const value = series.data[dataIndex];
40-
const color = value === null ? getSeriesColor({ value, dataIndex }) : yColorScale(value.y);
41-
if (color === null) {
37+
const color = yColorScale(value.y);
38+
if (typeof color !== 'string') {
4239
return getSeriesColor({ value, dataIndex });
4340
}
4441
return color;
@@ -51,8 +48,8 @@ const getColor: ColorProcessor<'scatter'> = (series, xAxis, yAxis, zAxis) => {
5148
return series.color;
5249
}
5350
const value = series.data[dataIndex];
54-
const color = value === null ? getSeriesColor({ value, dataIndex }) : xColorScale(value.x);
55-
if (color === null) {
51+
const color = xColorScale(value.x);
52+
if (typeof color !== 'string') {
5653
return getSeriesColor({ value, dataIndex });
5754
}
5855
return color;

packages/x-charts/src/internals/colorScale.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ export function getSequentialColorScale<Value extends number | Date>(
1414
config: ContinuousColorConfig<Value> | PiecewiseColorConfig<Value>,
1515
) {
1616
if (config.type === 'piecewise') {
17-
return scaleThreshold(config.thresholds, config.colors);
17+
return scaleThreshold(config.thresholds, config.colors).unknown(config.unknownColor ?? null);
1818
}
1919

20-
return scaleSequential([config.min ?? 0, config.max ?? 100], config.color);
20+
return scaleSequential([config.min ?? 0, config.max ?? 100], config.color).unknown(
21+
config.unknownColor ?? null,
22+
);
2123
}
2224

2325
export function getOrdinalColorScale<Value extends number | Date | string>(

packages/x-charts/src/internals/plugins/corePlugins/useChartSeriesConfig/types/colorProcessor.types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ export type ColorGetter<SeriesType extends ChartSeriesType> = SeriesType extends
1818
? (dataIndex: number) => string
1919
: SeriesType extends 'heatmap'
2020
? (value: number | null) => string
21-
: (dataIndex?: number) => string;
21+
: SeriesType extends 'mapShape'
22+
? (dataIndex?: number) => string | null
23+
: (dataIndex?: number) => string;
2224

2325
export type ColorProcessor<SeriesType extends ChartSeriesType> = (
2426
series: DefaultizedSeriesType<SeriesType>,

0 commit comments

Comments
 (0)