Venn chart
TIP
For core principles, concept description, API and changelog, refer to the D3 chart.
Basic usage
import React from 'react';
import { Chart } from '@semcore/d3-chart';
const Demo = () => {
return (
<div style={{ width: '500px' }}>
<Chart.Venn
data={data}
plotWidth={300}
plotHeight={300}
legendProps={legendProps}
aria-label={'Venn chart'}
/>
</div>
);
};
const data = {
G: 200,
F: 200,
C: 500,
U: 1,
'G/F': 100,
'G/C': 100,
'F/C': 100,
'G/F/C': 100, // intersection key must be `${key1}/${key2}/...`
};
const legendProps = {
legendMap: {
G: { label: 'Good' },
F: { label: 'Fast' },
C: { label: 'Clean' },
U: { label: 'Uniq' },
},
};
export default Demo;
Venn
A Venn chart allows you to see all kinds of intersections between two or more data sets.
Circle
are a component for circles.Intersection
is for intersections between the circles.
import React from 'react';
import { Plot, Venn, colors } from '@semcore/ui/d3-chart';
import { Text } from '@semcore/ui/typography';
const data = {
G: 200,
F: 200,
C: 500,
U: 1,
'G/F': 100,
'G/C': 100,
'F/C': 100,
'G/F/C': 100,
};
const Demo = () => {
return (
<Plot height={300} width={400} data={data}>
<Venn>
<Venn.Circle dataKey='G' name='Good' />
<Venn.Circle dataKey='F' name='Fast' />
<Venn.Circle dataKey='C' name='Cheap' />
<Venn.Circle dataKey='U' name='Unknown' />
<Venn.Intersection dataKey='G/F' name='Good & Fast' />
<Venn.Intersection dataKey='G/C' name='Good & Cheap' />
<Venn.Intersection dataKey='F/C' name='Fast & Cheap' />
<Venn.Intersection dataKey='G/F/C' name='Good & Fast & Cheap' />
</Venn>
<Venn.Tooltip>
{({ name, dataKey }) => {
return {
children: (
<>
<Venn.Tooltip.Title>{name}</Venn.Tooltip.Title>
<Text bold>{data[dataKey]}</Text>
</>
),
};
}}
</Venn.Tooltip>
</Plot>
);
};
export default Demo;
Custom intersection styles
If you want to change the intersection styles, you can add additional styles to the selected intersection.
import React from 'react';
import { Plot, Venn } from '@semcore/ui/d3-chart';
const Demo = () => {
return (
<Plot height={300} width={400} data={data}>
<Venn>
<Venn.Circle dataKey='G' name='G' />
<Venn.Circle dataKey='F' name='F' />
<Venn.Circle dataKey='C' name='C' />
<Venn.Intersection dataKey='G/F' name='G/F' />
<Venn.Intersection dataKey='G/C' name='G/C' />
<Venn.Intersection dataKey='F/C' name='F/C' />
<Venn.Intersection
dataKey='G/F/C'
name='G/F/C'
style={{
stroke: '#F00',
fill: '#0F0',
fillOpacity: 0.3,
}}
/>
</Venn>
</Plot>
);
};
const data = {
G: 200,
F: 200,
C: 200,
'G/F': 100,
'G/C': 100,
'F/C': 100,
'G/F/C': 100,
};
export default Demo;
Setting orientation
You can also change the orientation and stacking order of the circles.
import React from 'react';
import Button from '@semcore/ui/button';
import { colors, Plot, Venn } from '@semcore/ui/d3-chart';
import { Flex } from '@semcore/ui/flex-box';
const orders = [
(val1, val2) => val2.radius - val1.radius,
(val1, val2) => val1.radius - val2.radius,
];
const orientations = [Math.PI / 2, Math.PI];
const Demo = () => {
const [orientation, setOrientation] = React.useState(0);
const [order, setOrder] = React.useState(0);
return (
<Flex alignItems='flex-start' direction='column'>
<Plot height={300} width={400} data={data}>
<Venn orientation={orientations[orientation]} orientationOrder={orders[order]}>
<Venn.Circle dataKey='F' name='F' />
<Venn.Circle dataKey='S' name='S' />
<Venn.Intersection dataKey='F/S' name='F/S' />
</Venn>
</Plot>
<Flex direction='row'>
<Button onClick={() => setOrientation(Number(!orientation))} mr={2}>
Change orientation
</Button>
<Button onClick={() => setOrder(Number(!order))}>Change order</Button>
</Flex>
</Flex>
);
};
const data = {
F: 5,
S: 7,
'F/S': 3,
};
export default Demo;
Legend and pattern fill
Note that for ChartLegend patterns
property works only with default shape={'Checkbox'}
.
import React from 'react';
import { Plot, Venn } from '@semcore/ui/d3-chart';
import { Text } from '@semcore/ui/typography';
import { ChartLegend } from '@semcore/d3-chart';
const data = {
G: 200,
F: 200,
C: 500,
U: 1,
'G/F': 100,
'G/C': 100,
'F/C': 100,
'G/F/C': 100,
};
const defaultLegendItems = [
{
id: 'G',
label: 'Good',
checked: true,
color: 'chart-palette-order-1',
},
{
id: 'F',
label: 'Fast',
checked: true,
color: 'chart-palette-order-2',
},
{
id: 'C',
label: 'Cheap',
checked: true,
color: 'chart-palette-order-3',
},
{
id: 'U',
label: 'Unknown',
checked: true,
color: 'chart-palette-order-4',
},
];
const defaultIntersections = [
{
id: 'G/F',
label: 'Good & Fast',
visible: true,
},
{
id: 'G/C',
label: 'Fast',
visible: true,
},
{
id: 'F/C',
label: 'Cheap',
visible: true,
},
{
id: 'G/F/C',
label: 'Unknown',
visible: true,
},
];
const Demo = () => {
const [legendItems, setLegendItems] = React.useState(() => defaultLegendItems);
const intersectionItems = defaultIntersections.filter((intersection) => {
const intersectionKeys = intersection.id.split('/');
const disabled = intersectionKeys.some((key: string) => {
return !legendItems.find((item) => item.id === key)?.checked;
});
return !disabled;
});
const handleChangeVisible = React.useCallback((id: string, isVisible: boolean) => {
setLegendItems((prevItems) => {
const newItems = prevItems.map((item) => {
if (item.id === id) {
item.checked = isVisible;
}
return item;
});
return newItems;
});
}, []);
return (
<>
<ChartLegend
items={legendItems}
patterns
aria-label={'Legend for the venn chart'}
onChangeVisibleItem={handleChangeVisible}
/>
<Plot height={300} width={400} data={data} patterns>
<Venn>
{legendItems.map(({ id, label, checked, color }) => {
return checked && <Venn.Circle key={id} dataKey={id} name={label} color={color} />;
})}
{intersectionItems.map(({ id, label }) => (
<Venn.Intersection key={id} dataKey={id} name={label} />
))}
</Venn>
<Venn.Tooltip>
{({ name, dataKey }) => {
return {
children: (
<>
<Venn.Tooltip.Title>{name}</Venn.Tooltip.Title>
<Text bold>{data[dataKey]}</Text>
</>
),
};
}}
</Venn.Tooltip>
</Plot>
</>
);
};
export default Demo;