Skip to content

Commit

Permalink
[charts] Add domainLimit to axis config. (#15294)
Browse files Browse the repository at this point in the history
Co-authored-by: alex <[email protected]>
Co-authored-by: Jose Quintas <[email protected]>
  • Loading branch information
3 people authored and web-flow committed Nov 7, 2024
1 parent 5411114 commit a41a38e
Show file tree
Hide file tree
Showing 34 changed files with 396 additions and 26 deletions.
59 changes: 59 additions & 0 deletions docs/data/charts/axis/CustomDomainYAxis.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import { BarChart } from '@mui/x-charts/BarChart';
import TextField from '@mui/material/TextField';
import MenuItem from '@mui/material/MenuItem';

const settings = {
valueFormatter: (v) => `${v}%`,
height: 200,
showTooltip: true,
showHighlight: true,
series: [{ data: [60, -15, 66, 68, 87, 82, 83, 85, 92, 75, 76, 50, 91] }],
margin: { top: 10, bottom: 20 },
};

// Extend a value to match a multiple of the step.
function extend(value, step) {
if (value > 0) {
// If >0 go to the next step
return step * Math.ceil(value / step);
}
// If <0 go to the previous step
return step * Math.floor(value / step);
}

export default function CustomDomainYAxis() {
const [domainLimit, setDomainLimit] = React.useState('nice');

return (
<Box sx={{ width: '100%' }}>
<TextField
select
value={domainLimit}
onChange={(event) => setDomainLimit(event.target.value)}
label="domain limit"
sx={{ minWidth: 150, mb: 2 }}
>
<MenuItem value="nice">nice</MenuItem>
<MenuItem value="strict">strict</MenuItem>
<MenuItem value="function">function</MenuItem>
</TextField>

<BarChart
yAxis={[
{
domainLimit:
domainLimit === 'function'
? (min, max) => ({
min: extend(min, 10),
max: extend(max, 10),
})
: domainLimit,
},
]}
{...settings}
/>
</Box>
);
}
63 changes: 63 additions & 0 deletions docs/data/charts/axis/CustomDomainYAxis.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import { BarChart } from '@mui/x-charts/BarChart';
import TextField from '@mui/material/TextField';
import MenuItem from '@mui/material/MenuItem';

const settings = {
valueFormatter: (v: number | null) => `${v}%`,
height: 200,
showTooltip: true,
showHighlight: true,
series: [{ data: [60, -15, 66, 68, 87, 82, 83, 85, 92, 75, 76, 50, 91] }],
margin: { top: 10, bottom: 20 },
};

// Extend a value to match a multiple of the step.
function extend(value: number, step: number) {
if (value > 0) {
// If >0 go to the next step
return step * Math.ceil(value / step);
}
// If <0 go to the previous step
return step * Math.floor(value / step);
}

export default function CustomDomainYAxis() {
const [domainLimit, setDomainLimit] = React.useState<
'nice' | 'strict' | 'function'
>('nice');

return (
<Box sx={{ width: '100%' }}>
<TextField
select
value={domainLimit}
onChange={(event) =>
setDomainLimit(event.target.value as 'nice' | 'strict' | 'function')
}
label="domain limit"
sx={{ minWidth: 150, mb: 2 }}
>
<MenuItem value="nice">nice</MenuItem>
<MenuItem value="strict">strict</MenuItem>
<MenuItem value="function">function</MenuItem>
</TextField>

<BarChart
yAxis={[
{
domainLimit:
domainLimit === 'function'
? (min, max) => ({
min: extend(min, 10),
max: extend(max, 10),
})
: domainLimit,
},
]}
{...settings}
/>
</Box>
);
}
14 changes: 14 additions & 0 deletions docs/data/charts/axis/axis.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,20 @@ xAxis={[

{{"demo": "MinMaxExample.js"}}

### Relative axis sub domain

You can adjust the axis range relatively to its data by using the `domainLimit` option.
It can take 3 different values:

- `"nice"` Rounds the domain at human friendly values. It's the default behavior.
- `"strict"` Sets the domain to the min/max value to display.
- `([minValue, maxValue]) => [min, max]` Receives the calculated extremums as parameters, and should return the axis domain.

The demo below shows different ways to set the y-axis range.
They always display the same data, going from -15 to 92, but with different `domainLimit` settings.

{{"demo": "CustomDomainYAxis.js"}}

### Axis direction

By default, the axes' directions are left to right and bottom to top.
Expand Down
86 changes: 86 additions & 0 deletions docs/data/charts/sparkline/CustomDomainYAxis.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import * as React from 'react';
import TextField from '@mui/material/TextField';
import MenuItem from '@mui/material/MenuItem';
import Stack from '@mui/material/Stack';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';

import { SparkLineChart } from '@mui/x-charts/SparkLineChart';

const settings = {
valueFormatter: (v) => `${v}%`,
height: 100,
showTooltip: true,
showHighlight: true,
data: [60, -15, 66, 68, 87, 82, 83, 85, 92, 75, 76, 50, 91],
margin: { top: 10, bottom: 20, left: 5, right: 5 },
sx: (theme) => ({
borderWidth: 1,
borderStyle: 'solid',
borderColor: theme.palette.divider,
}),
};

// Extend a value to match a multiple of the step.
function extend(value, step) {
if (value > 0) {
// If >0 go to the next step
return step * Math.ceil(value / step);
}
// If <0 go to the previous step
return step * Math.floor(value / step);
}

const yRange = {
nice: '-100, 100',
strict: '-15, 92',
function: '-20, 100',
};
export default function CustomDomainYAxis() {
const [domainLimitKey, setDomainLimitKey] = React.useState('nice');

const domainLimit =
domainLimitKey === 'function'
? (min, max) => ({
min: extend(min, 10),
max: extend(max, 10),
})
: domainLimitKey;
return (
<Box
sx={{
width: '100%',
}}
>
<Stack direction="row" alignItems="baseline" justifyContent="space-between">
<TextField
select
value={domainLimitKey}
onChange={(event) => setDomainLimitKey(event.target.value)}
label="domain limit"
sx={{ minWidth: 150, mb: 2 }}
>
<MenuItem value="nice">nice</MenuItem>
<MenuItem value="strict">strict</MenuItem>
<MenuItem value="function">function</MenuItem>
</TextField>
<Typography>y-axis range: {yRange[domainLimitKey]}</Typography>
</Stack>

<Stack
sx={{
width: '100%',
}}
direction="row"
spacing={2}
>
<Box sx={{ flexGrow: 1 }}>
<SparkLineChart {...settings} yAxis={{ domainLimit }} />
</Box>
<Box sx={{ flexGrow: 1 }}>
<SparkLineChart plotType="bar" {...settings} yAxis={{ domainLimit }} />
</Box>
</Stack>
</Box>
);
}
90 changes: 90 additions & 0 deletions docs/data/charts/sparkline/CustomDomainYAxis.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import * as React from 'react';
import TextField from '@mui/material/TextField';
import MenuItem from '@mui/material/MenuItem';
import Stack from '@mui/material/Stack';
import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import { Theme } from '@mui/material/styles';
import { SparkLineChart } from '@mui/x-charts/SparkLineChart';

const settings = {
valueFormatter: (v: number | null) => `${v}%`,
height: 100,
showTooltip: true,
showHighlight: true,
data: [60, -15, 66, 68, 87, 82, 83, 85, 92, 75, 76, 50, 91],
margin: { top: 10, bottom: 20, left: 5, right: 5 },
sx: (theme: Theme) => ({
borderWidth: 1,
borderStyle: 'solid',
borderColor: theme.palette.divider,
}),
};

// Extend a value to match a multiple of the step.
function extend(value: number, step: number) {
if (value > 0) {
// If >0 go to the next step
return step * Math.ceil(value / step);
}
// If <0 go to the previous step
return step * Math.floor(value / step);
}

const yRange = {
nice: '-100, 100',
strict: '-15, 92',
function: '-20, 100',
};
export default function CustomDomainYAxis() {
const [domainLimitKey, setDomainLimitKey] = React.useState<
'nice' | 'strict' | 'function'
>('nice');

const domainLimit =
domainLimitKey === 'function'
? (min: number, max: number) => ({
min: extend(min, 10),
max: extend(max, 10),
})
: domainLimitKey;
return (
<Box
sx={{
width: '100%',
}}
>
<Stack direction="row" alignItems="baseline" justifyContent="space-between">
<TextField
select
value={domainLimitKey}
onChange={(event) =>
setDomainLimitKey(event.target.value as 'nice' | 'strict' | 'function')
}
label="domain limit"
sx={{ minWidth: 150, mb: 2 }}
>
<MenuItem value="nice">nice</MenuItem>
<MenuItem value="strict">strict</MenuItem>
<MenuItem value="function">function</MenuItem>
</TextField>
<Typography>y-axis range: {yRange[domainLimitKey]}</Typography>
</Stack>

<Stack
sx={{
width: '100%',
}}
direction="row"
spacing={2}
>
<Box sx={{ flexGrow: 1 }}>
<SparkLineChart {...settings} yAxis={{ domainLimit }} />
</Box>
<Box sx={{ flexGrow: 1 }}>
<SparkLineChart plotType="bar" {...settings} yAxis={{ domainLimit }} />
</Box>
</Stack>
</Box>
);
}
8 changes: 8 additions & 0 deletions docs/data/charts/sparkline/sparkline.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,11 @@ The following demo shows two sparklines, one with small and another with large v
The first row has the default y-axis values, while on the second row a fixed range from `0` to `100` has been set.

{{"demo": "CustomYAxis.js"}}

You can adjust the y-axis range of a sparkline relatively to its data by using the `domainLimit` option in the `yAxis` configuration.
See the [axis docs page](http://localhost:3001/x/react-charts/axis/#relative-axis-sub-domain) form more information.

The demo below shows different ways to set the y-axis range.
They always display the same data, going from -15 to 92, but with different `domainLimit` settings.

{{"demo": "CustomDomainYAxis.js"}}
5 changes: 5 additions & 0 deletions docs/pages/x/api/charts/axis-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
},
"data": { "type": { "description": "V[]" } },
"dataKey": { "type": { "description": "string" } },
"domainLimit": {
"type": {
"description": "'nice' | 'strict' | ((min: number, max: number) =&gt; { min: number; max: number })"
}
},
"hideTooltip": { "type": { "description": "boolean" } },
"max": { "type": { "description": "number | Date" } },
"min": { "type": { "description": "number | Date" } },
Expand Down
4 changes: 2 additions & 2 deletions docs/pages/x/api/charts/bar-chart-pro.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,13 @@
"xAxis": {
"type": {
"name": "arrayOf",
"description": "Array&lt;{ classes?: object, colorMap?: { colors: Array&lt;string&gt;, type: 'ordinal', unknownColor?: string, values?: Array&lt;Date<br>&#124;&nbsp;number<br>&#124;&nbsp;string&gt; }<br>&#124;&nbsp;{ color: Array&lt;string&gt;<br>&#124;&nbsp;func, max?: Date<br>&#124;&nbsp;number, min?: Date<br>&#124;&nbsp;number, type: 'continuous' }<br>&#124;&nbsp;{ colors: Array&lt;string&gt;, thresholds: Array&lt;Date<br>&#124;&nbsp;number&gt;, type: 'piecewise' }, data?: array, dataKey?: string, disableLine?: bool, disableTicks?: bool, fill?: string, hideTooltip?: bool, id?: number<br>&#124;&nbsp;string, label?: string, labelFontSize?: number, labelStyle?: object, max?: Date<br>&#124;&nbsp;number, min?: Date<br>&#124;&nbsp;number, position?: 'bottom'<br>&#124;&nbsp;'top', reverse?: bool, scaleType?: 'band'<br>&#124;&nbsp;'linear'<br>&#124;&nbsp;'log'<br>&#124;&nbsp;'point'<br>&#124;&nbsp;'pow'<br>&#124;&nbsp;'sqrt'<br>&#124;&nbsp;'time'<br>&#124;&nbsp;'utc', slotProps?: object, slots?: object, stroke?: string, sx?: Array&lt;func<br>&#124;&nbsp;object<br>&#124;&nbsp;bool&gt;<br>&#124;&nbsp;func<br>&#124;&nbsp;object, tickFontSize?: number, tickInterval?: 'auto'<br>&#124;&nbsp;array<br>&#124;&nbsp;func, tickLabelInterval?: 'auto'<br>&#124;&nbsp;func, tickLabelPlacement?: 'middle'<br>&#124;&nbsp;'tick', tickLabelStyle?: object, tickMaxStep?: number, tickMinStep?: number, tickNumber?: number, tickPlacement?: 'end'<br>&#124;&nbsp;'extremities'<br>&#124;&nbsp;'middle'<br>&#124;&nbsp;'start', tickSize?: number, valueFormatter?: func, zoom?: { filterMode?: 'discard'<br>&#124;&nbsp;'keep', maxEnd?: number, maxSpan?: number, minSpan?: number, minStart?: number, panning?: bool, step?: number }<br>&#124;&nbsp;bool }&gt;"
"description": "Array&lt;{ classes?: object, colorMap?: { colors: Array&lt;string&gt;, type: 'ordinal', unknownColor?: string, values?: Array&lt;Date<br>&#124;&nbsp;number<br>&#124;&nbsp;string&gt; }<br>&#124;&nbsp;{ color: Array&lt;string&gt;<br>&#124;&nbsp;func, max?: Date<br>&#124;&nbsp;number, min?: Date<br>&#124;&nbsp;number, type: 'continuous' }<br>&#124;&nbsp;{ colors: Array&lt;string&gt;, thresholds: Array&lt;Date<br>&#124;&nbsp;number&gt;, type: 'piecewise' }, data?: array, dataKey?: string, disableLine?: bool, disableTicks?: bool, domainLimit?: 'nice'<br>&#124;&nbsp;'strict'<br>&#124;&nbsp;func, fill?: string, hideTooltip?: bool, id?: number<br>&#124;&nbsp;string, label?: string, labelFontSize?: number, labelStyle?: object, max?: Date<br>&#124;&nbsp;number, min?: Date<br>&#124;&nbsp;number, position?: 'bottom'<br>&#124;&nbsp;'top', reverse?: bool, scaleType?: 'band'<br>&#124;&nbsp;'linear'<br>&#124;&nbsp;'log'<br>&#124;&nbsp;'point'<br>&#124;&nbsp;'pow'<br>&#124;&nbsp;'sqrt'<br>&#124;&nbsp;'time'<br>&#124;&nbsp;'utc', slotProps?: object, slots?: object, stroke?: string, sx?: Array&lt;func<br>&#124;&nbsp;object<br>&#124;&nbsp;bool&gt;<br>&#124;&nbsp;func<br>&#124;&nbsp;object, tickFontSize?: number, tickInterval?: 'auto'<br>&#124;&nbsp;array<br>&#124;&nbsp;func, tickLabelInterval?: 'auto'<br>&#124;&nbsp;func, tickLabelPlacement?: 'middle'<br>&#124;&nbsp;'tick', tickLabelStyle?: object, tickMaxStep?: number, tickMinStep?: number, tickNumber?: number, tickPlacement?: 'end'<br>&#124;&nbsp;'extremities'<br>&#124;&nbsp;'middle'<br>&#124;&nbsp;'start', tickSize?: number, valueFormatter?: func, zoom?: { filterMode?: 'discard'<br>&#124;&nbsp;'keep', maxEnd?: number, maxSpan?: number, minSpan?: number, minStart?: number, panning?: bool, step?: number }<br>&#124;&nbsp;bool }&gt;"
}
},
"yAxis": {
"type": {
"name": "arrayOf",
"description": "Array&lt;{ classes?: object, colorMap?: { colors: Array&lt;string&gt;, type: 'ordinal', unknownColor?: string, values?: Array&lt;Date<br>&#124;&nbsp;number<br>&#124;&nbsp;string&gt; }<br>&#124;&nbsp;{ color: Array&lt;string&gt;<br>&#124;&nbsp;func, max?: Date<br>&#124;&nbsp;number, min?: Date<br>&#124;&nbsp;number, type: 'continuous' }<br>&#124;&nbsp;{ colors: Array&lt;string&gt;, thresholds: Array&lt;Date<br>&#124;&nbsp;number&gt;, type: 'piecewise' }, data?: array, dataKey?: string, disableLine?: bool, disableTicks?: bool, fill?: string, hideTooltip?: bool, id?: number<br>&#124;&nbsp;string, label?: string, labelFontSize?: number, labelStyle?: object, max?: Date<br>&#124;&nbsp;number, min?: Date<br>&#124;&nbsp;number, position?: 'left'<br>&#124;&nbsp;'right', reverse?: bool, scaleType?: 'band'<br>&#124;&nbsp;'linear'<br>&#124;&nbsp;'log'<br>&#124;&nbsp;'point'<br>&#124;&nbsp;'pow'<br>&#124;&nbsp;'sqrt'<br>&#124;&nbsp;'time'<br>&#124;&nbsp;'utc', slotProps?: object, slots?: object, stroke?: string, sx?: Array&lt;func<br>&#124;&nbsp;object<br>&#124;&nbsp;bool&gt;<br>&#124;&nbsp;func<br>&#124;&nbsp;object, tickFontSize?: number, tickInterval?: 'auto'<br>&#124;&nbsp;array<br>&#124;&nbsp;func, tickLabelInterval?: 'auto'<br>&#124;&nbsp;func, tickLabelPlacement?: 'middle'<br>&#124;&nbsp;'tick', tickLabelStyle?: object, tickMaxStep?: number, tickMinStep?: number, tickNumber?: number, tickPlacement?: 'end'<br>&#124;&nbsp;'extremities'<br>&#124;&nbsp;'middle'<br>&#124;&nbsp;'start', tickSize?: number, valueFormatter?: func, zoom?: { filterMode?: 'discard'<br>&#124;&nbsp;'keep', maxEnd?: number, maxSpan?: number, minSpan?: number, minStart?: number, panning?: bool, step?: number }<br>&#124;&nbsp;bool }&gt;"
"description": "Array&lt;{ classes?: object, colorMap?: { colors: Array&lt;string&gt;, type: 'ordinal', unknownColor?: string, values?: Array&lt;Date<br>&#124;&nbsp;number<br>&#124;&nbsp;string&gt; }<br>&#124;&nbsp;{ color: Array&lt;string&gt;<br>&#124;&nbsp;func, max?: Date<br>&#124;&nbsp;number, min?: Date<br>&#124;&nbsp;number, type: 'continuous' }<br>&#124;&nbsp;{ colors: Array&lt;string&gt;, thresholds: Array&lt;Date<br>&#124;&nbsp;number&gt;, type: 'piecewise' }, data?: array, dataKey?: string, disableLine?: bool, disableTicks?: bool, domainLimit?: 'nice'<br>&#124;&nbsp;'strict'<br>&#124;&nbsp;func, fill?: string, hideTooltip?: bool, id?: number<br>&#124;&nbsp;string, label?: string, labelFontSize?: number, labelStyle?: object, max?: Date<br>&#124;&nbsp;number, min?: Date<br>&#124;&nbsp;number, position?: 'left'<br>&#124;&nbsp;'right', reverse?: bool, scaleType?: 'band'<br>&#124;&nbsp;'linear'<br>&#124;&nbsp;'log'<br>&#124;&nbsp;'point'<br>&#124;&nbsp;'pow'<br>&#124;&nbsp;'sqrt'<br>&#124;&nbsp;'time'<br>&#124;&nbsp;'utc', slotProps?: object, slots?: object, stroke?: string, sx?: Array&lt;func<br>&#124;&nbsp;object<br>&#124;&nbsp;bool&gt;<br>&#124;&nbsp;func<br>&#124;&nbsp;object, tickFontSize?: number, tickInterval?: 'auto'<br>&#124;&nbsp;array<br>&#124;&nbsp;func, tickLabelInterval?: 'auto'<br>&#124;&nbsp;func, tickLabelPlacement?: 'middle'<br>&#124;&nbsp;'tick', tickLabelStyle?: object, tickMaxStep?: number, tickMinStep?: number, tickNumber?: number, tickPlacement?: 'end'<br>&#124;&nbsp;'extremities'<br>&#124;&nbsp;'middle'<br>&#124;&nbsp;'start', tickSize?: number, valueFormatter?: func, zoom?: { filterMode?: 'discard'<br>&#124;&nbsp;'keep', maxEnd?: number, maxSpan?: number, minSpan?: number, minStart?: number, panning?: bool, step?: number }<br>&#124;&nbsp;bool }&gt;"
}
},
"zoom": {
Expand Down
Loading

0 comments on commit a41a38e

Please sign in to comment.