Radar chart
TIP
For core principles, concept description, API and changelog, refer to the D3 chart.
Basic usage
import { Chart, colors } from '@semcore/ui/d3-chart';
import React from 'react';
import RadarMockData from './mock';
const Demo = () => {
return (
<Chart.Radar
data={data}
groupKey='categories'
plotWidth={400}
plotHeight={400}
aria-label='Radar chart'
/>
);
};
const data = RadarMockData.Default;
export default Demo;
Scale
You must pass a scale with a specified domain, range doesn't need to be specified as it is calculated automatically. You can modify the range or use a non-linear scale.
import { Flex } from '@semcore/ui/base-components';
import { Plot, Radar } from '@semcore/ui/d3-chart';
import { scaleLinear } from 'd3-scale';
import React from 'react';
import RadarMockData from './mock';
const Demo = () => {
const width = 250;
const height = 250;
const scale_1 = scaleLinear().domain([0, 10]);
const scale_2 = scaleLinear().domain([0, 20]);
return (
<Flex>
<Plot data={data} width={width} height={height}>
<Radar scale={scale_1}>
<Radar.Axis dataKey='categories'>
<Radar.Axis.Ticks />
<Radar.Axis.Labels />
</Radar.Axis>
<Radar.Polygon dataKey='data_1'>
<Radar.Polygon.Line />
<Radar.Polygon.Dots />
</Radar.Polygon>
</Radar>
</Plot>
<Plot data={data} width={width} height={height}>
<Radar scale={scale_2}>
<Radar.Axis dataKey='categories'>
<Radar.Axis.Ticks />
<Radar.Axis.Labels />
</Radar.Axis>
<Radar.Polygon dataKey='data_1'>
<Radar.Polygon.Line />
<Radar.Polygon.Dots />
</Radar.Polygon>
</Radar>
</Plot>
</Flex>
);
};
const data = RadarMockData.SingleData;
export default Demo;
Color
You can change the color by passing the color property to the <Radar.Polygon/>. It is also possible to pass the 'color' property to <Radar.Polygon.Line/> and <Radar.Polygon.Dots/>.
import { Plot, Radar } from '@semcore/ui/d3-chart';
import { scaleLinear } from 'd3-scale';
import React from 'react';
import RadarMockData from './mock';
const Demo = () => {
const width = 500;
const height = 500;
const scale = scaleLinear().domain([0, 10]);
return (
<Plot data={data} width={width} height={height}>
<Radar scale={scale}>
<Radar.Axis dataKey='categories'>
<Radar.Axis.Ticks />
<Radar.Axis.Labels />
</Radar.Axis>
<Radar.Polygon dataKey='data_1' color='chart-palette-order-1'>
<Radar.Polygon.Line />
<Radar.Polygon.Dots />
</Radar.Polygon>
<Radar.Polygon dataKey='data_2' color='chart-palette-order-2'>
<Radar.Polygon.Line />
<Radar.Polygon.Dots />
</Radar.Polygon>
</Radar>
</Plot>
);
};
const data = RadarMockData.Default;
export default Demo;
Background color
You can use the fill="transparent" property to make polygons transparent.
import { Plot, Radar, colors } from '@semcore/ui/d3-chart';
import { scaleLinear } from 'd3-scale';
import React from 'react';
import RadarMockData from './mock';
const Demo = () => {
const width = 500;
const height = 500;
const scale = scaleLinear().domain([0, 10]);
return (
<Plot data={data} width={width} height={height}>
<Radar scale={scale}>
<Radar.Axis dataKey='categories'>
<Radar.Axis.Ticks />
<Radar.Axis.Labels />
</Radar.Axis>
<Radar.Polygon dataKey='data_1' color='chart-palette-order-1' fill='transparent'>
<Radar.Polygon.Line />
<Radar.Polygon.Dots />
</Radar.Polygon>
<Radar.Polygon dataKey='data_2' color='chart-palette-order-2' fill='transparent'>
<Radar.Polygon.Line />
<Radar.Polygon.Dots />
</Radar.Polygon>
</Radar>
</Plot>
);
};
const data = RadarMockData.Default;
export default Demo;
Label long
If your labels are too long, you can move them to the next line using the line break symbol \n.
import { Flex } from '@semcore/ui/base-components';
import { Plot, Radar } from '@semcore/ui/d3-chart';
import { scaleLinear } from 'd3-scale';
import React from 'react';
import RadarMockData from './mock';
const Demo = () => {
const width = 250;
const height = 250;
const scale = scaleLinear().domain([0, 10]);
return (
<Flex>
<Plot data={data} width={width} height={height}>
<Radar scale={scale}>
<Radar.Axis dataKey='categories'>
<Radar.Axis.Ticks />
<Radar.Axis.Labels />
</Radar.Axis>
<Radar.Polygon dataKey='data_1'>
<Radar.Polygon.Line />
<Radar.Polygon.Dots />
</Radar.Polygon>
</Radar>
</Plot>
</Flex>
);
};
const data = RadarMockData.LongLabel;
export default Demo;
Label custom
If you need a custom React component instead of a label, you can change the display in the render function.
import { Flex } from '@semcore/ui/base-components';
import { Plot, Radar, getLabelOffsetPosition } from '@semcore/ui/d3-chart';
import Tag from '@semcore/ui/tag';
import { scaleLinear } from 'd3-scale';
import React from 'react';
import RadarMockData from './mock';
const Demo = () => {
const width = 250;
const height = 250;
const scale = scaleLinear().domain([0, 10]);
const maxLabelWidth = 50;
return (
<Flex>
<Plot data={data} width={width} height={height}>
<Radar scale={scale} offset={maxLabelWidth}>
<Radar.Axis dataKey='categories'>
<Radar.Axis.Ticks />
<Radar.Axis.Labels>
{(props) => {
const width = maxLabelWidth;
const height = 20;
const [xOffset, yOffset] = getLabelOffsetPosition(
props.xDirection,
props.yDirection,
width,
height,
);
return {
tag: 'g',
children: (
<foreignObject
x={props.x - xOffset}
y={props.y - yOffset}
width={width}
height={height}
>
<Tag>{props.children}</Tag>
</foreignObject>
),
};
}}
</Radar.Axis.Labels>
</Radar.Axis>
<Radar.Polygon dataKey='data_1'>
<Radar.Polygon.Line />
<Radar.Polygon.Dots />
</Radar.Polygon>
</Radar>
</Plot>
</Flex>
);
};
const data = RadarMockData.SingleData;
export default Demo;
Tooltip
You need to use the <Radar.Tooltip /> component to add interactivity.
import { Plot, Radar } from '@semcore/ui/d3-chart';
import { scaleLinear } from 'd3-scale';
import React from 'react';
import RadarMockData from './mock';
const Demo = () => {
const width = 500;
const height = 500;
const scale = scaleLinear().domain([0, 10]);
return (
<Plot data={data} width={width} height={height}>
<Radar scale={scale}>
<Radar.Axis dataKey='categories'>
<Radar.Axis.Ticks />
<Radar.Axis.Labels />
</Radar.Axis>
<Radar.Tooltip wMin={100}>
{({ index }) => {
return {
children: (
<>
<Radar.Tooltip.Title>{data.categories[index]}</Radar.Tooltip.Title>
<Radar.Tooltip.Dot>{data['data_1'][index]}</Radar.Tooltip.Dot>
<Radar.Tooltip.Dot>{data['data_2'][index]}</Radar.Tooltip.Dot>
</>
),
};
}}
</Radar.Tooltip>
<Radar.Polygon dataKey='data_1'>
<Radar.Polygon.Line />
<Radar.Polygon.Dots />
</Radar.Polygon>
<Radar.Polygon dataKey='data_2'>
<Radar.Polygon.Line />
<Radar.Polygon.Dots />
</Radar.Polygon>
</Radar>
</Plot>
);
};
const data = RadarMockData.Default;
export default Demo;
Circle
To make the chart round, you need to pass the parameter type="circle". You can also round the polygons by passing the "curve" parameter from D3 into them.
import { Plot, Radar } from '@semcore/ui/d3-chart';
import { scaleLinear } from 'd3-scale';
import { curveCardinalClosed } from 'd3-shape';
import React from 'react';
import RadarMockData from './mock';
const Demo = () => {
const width = 500;
const height = 500;
const scale = scaleLinear().domain([0, 10]);
return (
<Plot data={data} width={width} height={height}>
<Radar scale={scale} type='circle'>
<Radar.Axis dataKey='categories'>
<Radar.Axis.Ticks />
<Radar.Axis.Labels />
</Radar.Axis>
<Radar.Tooltip wMin={100}>
{({ index }) => {
return {
children: (
<>
<Radar.Tooltip.Title>{data.categories[index]}</Radar.Tooltip.Title>
<Radar.Tooltip.Dot>{data['data_1'][index]}</Radar.Tooltip.Dot>
<Radar.Tooltip.Dot>{data['data_2'][index]}</Radar.Tooltip.Dot>
</>
),
};
}}
</Radar.Tooltip>
<Radar.Polygon dataKey='data_1' curve={curveCardinalClosed}>
<Radar.Polygon.Line />
<Radar.Polygon.Dots />
</Radar.Polygon>
<Radar.Polygon dataKey='data_2' curve={curveCardinalClosed}>
<Radar.Polygon.Line />
<Radar.Polygon.Dots />
</Radar.Polygon>
</Radar>
</Plot>
);
};
const data = RadarMockData.Default;
export default Demo;
Tick size
To change the distance between the grid lines, you need to change the value of the tickSize parameter.
import { Plot, Radar } from '@semcore/ui/d3-chart';
import { scaleLinear } from 'd3-scale';
import React from 'react';
import RadarMockData from './mock';
const Demo = () => {
const width = 500;
const height = 500;
const scale = scaleLinear().domain([0, 10]);
return (
<Plot data={data} width={width} height={height}>
<Radar scale={scale}>
<Radar.Axis dataKey='categories'>
<Radar.Axis.Ticks tickSize={30} />
<Radar.Axis.Labels />
</Radar.Axis>
<Radar.Polygon dataKey='data_1'>
<Radar.Polygon.Line />
<Radar.Polygon.Dots />
</Radar.Polygon>
<Radar.Polygon dataKey='data_2'>
<Radar.Polygon.Line />
<Radar.Polygon.Dots />
</Radar.Polygon>
</Radar>
</Plot>
);
};
const data = RadarMockData.Default;
export default Demo;
Rotated
To change base angle of the chart, set angleOffset (in radians) parameter.
import { Plot, Radar } from '@semcore/ui/d3-chart';
import Slider from '@semcore/ui/slider';
import { scaleLinear } from 'd3-scale';
import { curveCardinalClosed } from 'd3-shape';
import React from 'react';
import RadarMockData from './mock';
const scale = scaleLinear().domain([0, 10]);
const Demo = () => {
const width = 500;
const height = 500;
const [angleDegOffset, setAngleDegOffset] = React.useState(45);
const angleOffset = React.useMemo(() => (angleDegOffset / 180) * Math.PI, [angleDegOffset]);
return (
<div>
<Slider
value={angleDegOffset}
onChange={setAngleDegOffset}
step={1}
min={-360}
max={360}
w={360}
id='angle-slider'
/>
<div>
<label htmlFor='angle-slider'>Angle:</label>
{' '}
{angleOffset.toFixed(2)}
{' '}
rad (
{angleDegOffset.toFixed(0)}
{' '}
deg)
</div>
<Plot data={data} width={width} height={height}>
<Radar scale={scale} type='circle' angleOffset={angleOffset}>
<Radar.Axis dataKey='categories'>
<Radar.Axis.Ticks />
<Radar.Axis.Labels />
</Radar.Axis>
<Radar.Tooltip wMin={100}>
{({ index }) => {
return {
children: (
<>
<Radar.Tooltip.Title>{data.categories[index]}</Radar.Tooltip.Title>
<Radar.Tooltip.Dot>{data['data_1'][index]}</Radar.Tooltip.Dot>
<Radar.Tooltip.Dot>{data['data_2'][index]}</Radar.Tooltip.Dot>
</>
),
};
}}
</Radar.Tooltip>
<Radar.Polygon dataKey='data_1' curve={curveCardinalClosed}>
<Radar.Polygon.Line />
<Radar.Polygon.Dots />
</Radar.Polygon>
<Radar.Polygon dataKey='data_2' curve={curveCardinalClosed}>
<Radar.Polygon.Line />
<Radar.Polygon.Dots />
</Radar.Polygon>
</Radar>
</Plot>
</div>
);
};
const data = RadarMockData.Default;
export default Demo;
Legend and pattern fill
Note that for ChartLegend patterns property works only with default shape={'Checkbox'}.
import { Plot, Radar, colors, ChartLegend } from '@semcore/ui/d3-chart';
import { scaleLinear } from 'd3-scale';
import React from 'react';
import RadarMockData from './mock';
type DataKey = keyof typeof data;
const getDefaultLegendItems = () => {
return (Object.keys(data) as DataKey[])
.filter((name) => name !== 'categories')
.map((item, index) => {
return {
id: item,
label: `Category ${index + 1}`,
data: data[item],
checked: true,
color: lineColors[item],
};
});
};
const Demo = () => {
const [legendItems, setLegendItems] = React.useState(getDefaultLegendItems);
const handleChangeVisible = React.useCallback((id: string, isVisible: boolean) => {
setLegendItems((prevItems) =>
prevItems.map((item) =>
item.id === id ? { ...item, checked: isVisible } : item,
),
);
}, []);
const width = 500;
const height = 500;
const scale = scaleLinear().domain([0, 10]);
return (
<>
<ChartLegend
items={legendItems}
patterns
aria-label='Radar chart legend'
onChangeVisibleItem={handleChangeVisible}
/>
<Plot data={data} width={width} height={height} patterns>
<Radar scale={scale}>
<Radar.Axis dataKey='categories'>
<Radar.Axis.Ticks />
<Radar.Axis.Labels />
</Radar.Axis>
{legendItems.map(
(item) =>
item.checked && (
<Radar.Polygon key={item.id} dataKey={item.id} color={item.color}>
<Radar.Polygon.Line />
<Radar.Polygon.Dots />
</Radar.Polygon>
),
)}
</Radar>
</Plot>
</>
);
};
const data = RadarMockData.Default;
const lineColors: Record<keyof typeof data, string> = {
categories: '',
data_1: colors['orange-04'],
data_2: colors['violet-04'],
};
export default Demo;