TIP
For core principles, concept description, API and changelog, refer to the D3 chart.
Basic usage
tsx
import React from 'react';
import { Chart } from 'intergalactic/d3-chart';
const Demo = () => {
return (
<Chart.Bar
groupKey={'category'}
data={data}
plotWidth={500}
plotHeight={300}
invertAxis={true}
/>
);
};
const data = Array(5)
.fill({})
.map((d, i) => ({
category: `Category ${i}`,
bar: Math.random() * 10,
}));
export default Demo;
import React from 'react';
import { Chart } from 'intergalactic/d3-chart';
const Demo = () => {
return (
<Chart.Bar
groupKey={'category'}
data={data}
plotWidth={500}
plotHeight={300}
invertAxis={true}
/>
);
};
const data = Array(5)
.fill({})
.map((d, i) => ({
category: `Category ${i}`,
bar: Math.random() * 10,
}));
export default Demo;
Horizontal bar
You can rotate a chart using the <HorizontalBar/>
component by swapping scaleBand
and scaleLinear
. See more about scaleBand
and scaleLiner
in the Bar chart guide.
tsx
import React from 'react';
import { Plot, HorizontalBar, YAxis, XAxis, HoverRect } from 'intergalactic/d3-chart';
import { scaleLinear, scaleBand } from 'd3-scale';
import { Flex } from 'intergalactic/flex-box';
import { Text } from 'intergalactic/typography';
const Demo = () => {
const MARGIN = 40;
const width = 500;
const height = 300;
const xScale = scaleLinear()
.range([MARGIN * 2, width - MARGIN])
.domain([0, 10]);
const yScale = scaleBand()
.range([height - MARGIN, MARGIN])
.domain(data.map((d) => d.category))
.paddingInner(0.4)
.paddingOuter(0.2);
return (
<Plot data={data} scale={[xScale, yScale]} width={width} height={height}>
<YAxis hide={false}>
<YAxis.Ticks />
</YAxis>
<XAxis>
<XAxis.Ticks />
<XAxis.Grid />
</XAxis>
<HoverRect.Tooltip y='category' wMin={100}>
{({ yIndex }) => {
return {
children: (
<>
<HoverRect.Tooltip.Title>{data[yIndex].category}</HoverRect.Tooltip.Title>
<Flex justifyContent='space-between'>
<HoverRect.Tooltip.Dot mr={4}>Bar</HoverRect.Tooltip.Dot>
<Text bold>{data[yIndex].bar}</Text>
</Flex>
</>
),
};
}}
</HoverRect.Tooltip>
<HorizontalBar x='bar' y='category' />
</Plot>
);
};
const data = [...Array(5).keys()].map((d, i) => ({
category: `Category ${i}`,
bar: Math.random() * 10,
}));
export default Demo;
import React from 'react';
import { Plot, HorizontalBar, YAxis, XAxis, HoverRect } from 'intergalactic/d3-chart';
import { scaleLinear, scaleBand } from 'd3-scale';
import { Flex } from 'intergalactic/flex-box';
import { Text } from 'intergalactic/typography';
const Demo = () => {
const MARGIN = 40;
const width = 500;
const height = 300;
const xScale = scaleLinear()
.range([MARGIN * 2, width - MARGIN])
.domain([0, 10]);
const yScale = scaleBand()
.range([height - MARGIN, MARGIN])
.domain(data.map((d) => d.category))
.paddingInner(0.4)
.paddingOuter(0.2);
return (
<Plot data={data} scale={[xScale, yScale]} width={width} height={height}>
<YAxis hide={false}>
<YAxis.Ticks />
</YAxis>
<XAxis>
<XAxis.Ticks />
<XAxis.Grid />
</XAxis>
<HoverRect.Tooltip y='category' wMin={100}>
{({ yIndex }) => {
return {
children: (
<>
<HoverRect.Tooltip.Title>{data[yIndex].category}</HoverRect.Tooltip.Title>
<Flex justifyContent='space-between'>
<HoverRect.Tooltip.Dot mr={4}>Bar</HoverRect.Tooltip.Dot>
<Text bold>{data[yIndex].bar}</Text>
</Flex>
</>
),
};
}}
</HoverRect.Tooltip>
<HorizontalBar x='bar' y='category' />
</Plot>
);
};
const data = [...Array(5).keys()].map((d, i) => ({
category: `Category ${i}`,
bar: Math.random() * 10,
}));
export default Demo;
Bar labels
To draw the values of the bars, pass the function to <Bar/>
to receive all required values.
tsx
import React from 'react';
import { Plot, HorizontalBar, YAxis } from 'intergalactic/d3-chart';
import { scaleLinear, scaleBand } from 'd3-scale';
import { useColorResolver } from 'intergalactic/utils/lib/use/useColorResolver';
const Demo = () => {
const MARGIN = 40;
const width = 500;
const height = 300;
const resolveColor = useColorResolver();
const xScale = scaleLinear()
.range([MARGIN * 2, width - MARGIN * 2])
.domain([0, Math.max(...data.map((d) => Number.parseFloat(d.bar)))]);
const yScale = scaleBand()
.range([height - MARGIN, MARGIN])
.domain(data.map((d) => d.category))
.paddingInner(0.4)
.paddingOuter(0.2);
return (
<Plot data={data} scale={[xScale, yScale]} width={width} height={height}>
<YAxis>
<YAxis.Ticks />
</YAxis>
<HorizontalBar x='bar' y='category'>
{({ index, x, y, width, height }) => {
return {
children: (
<text
x={x + width + 16}
y={y + height / 2}
textAnchor='start'
alignmentBaseline='middle'
fill={resolveColor('--intergalactic-text-secondary')}
>
$ {data[index].bar}
</text>
),
};
}}
</HorizontalBar>
</Plot>
);
};
const data = [...Array(5).keys()].map((d, i) => ({
category: `Category ${i}`,
bar: i + (Math.random() * 10).toFixed(2),
}));
export default Demo;
import React from 'react';
import { Plot, HorizontalBar, YAxis } from 'intergalactic/d3-chart';
import { scaleLinear, scaleBand } from 'd3-scale';
import { useColorResolver } from 'intergalactic/utils/lib/use/useColorResolver';
const Demo = () => {
const MARGIN = 40;
const width = 500;
const height = 300;
const resolveColor = useColorResolver();
const xScale = scaleLinear()
.range([MARGIN * 2, width - MARGIN * 2])
.domain([0, Math.max(...data.map((d) => Number.parseFloat(d.bar)))]);
const yScale = scaleBand()
.range([height - MARGIN, MARGIN])
.domain(data.map((d) => d.category))
.paddingInner(0.4)
.paddingOuter(0.2);
return (
<Plot data={data} scale={[xScale, yScale]} width={width} height={height}>
<YAxis>
<YAxis.Ticks />
</YAxis>
<HorizontalBar x='bar' y='category'>
{({ index, x, y, width, height }) => {
return {
children: (
<text
x={x + width + 16}
y={y + height / 2}
textAnchor='start'
alignmentBaseline='middle'
fill={resolveColor('--intergalactic-text-secondary')}
>
$ {data[index].bar}
</text>
),
};
}}
</HorizontalBar>
</Plot>
);
};
const data = [...Array(5).keys()].map((d, i) => ({
category: `Category ${i}`,
bar: i + (Math.random() * 10).toFixed(2),
}));
export default Demo;
Grouped horizontal bars
To combine multiple horizontal bars, use <GroupBar.HorizontalBar/>
.
TIP
The <GroupBar.HorizontalBar/>
component is a customized <HorizontalBar/>
that has the same API.
tsx
import React from 'react';
import { Plot, GroupBar, YAxis, XAxis, HoverRect } from 'intergalactic/d3-chart';
import { scaleLinear, scaleBand } from 'd3-scale';
import { Flex } from 'intergalactic/flex-box';
import { Text } from 'intergalactic/typography';
const Demo = () => {
const MARGIN = 40;
const width = 500;
const height = 300;
const xScale = scaleLinear()
.range([MARGIN * 2, width - MARGIN])
.domain([0, 10]);
const yScale = scaleBand()
.range([height - MARGIN, MARGIN])
.domain(data.map((d) => d.category))
.paddingInner(0.4)
.paddingOuter(0.2);
return (
<Plot data={data} scale={[xScale, yScale]} width={width} height={height}>
<YAxis hide={false}>
<YAxis.Ticks />
</YAxis>
<XAxis>
<XAxis.Ticks />
<XAxis.Grid />
</XAxis>
<HoverRect.Tooltip y='category' wMin={100}>
{({ yIndex }) => {
return {
children: (
<>
<HoverRect.Tooltip.Title>{data[yIndex].category}</HoverRect.Tooltip.Title>
<Flex justifyContent='space-between'>
<HoverRect.Tooltip.Dot mr={4}>Bar 1</HoverRect.Tooltip.Dot>
<Text bold>{data[yIndex].bar1}</Text>
</Flex>
<Flex mt={2} justifyContent='space-between'>
<HoverRect.Tooltip.Dot mr={4}>Bar 2</HoverRect.Tooltip.Dot>
<Text bold>{data[yIndex].bar2}</Text>
</Flex>
</>
),
};
}}
</HoverRect.Tooltip>
<GroupBar y='category'>
<GroupBar.HorizontalBar x='bar1' />
<GroupBar.HorizontalBar x='bar2' />
</GroupBar>
</Plot>
);
};
const data = [...Array(5).keys()].map((d, i) => ({
category: `Category ${i}`,
bar1: Math.random() * 10,
bar2: Math.random() * 10,
}));
export default Demo;
import React from 'react';
import { Plot, GroupBar, YAxis, XAxis, HoverRect } from 'intergalactic/d3-chart';
import { scaleLinear, scaleBand } from 'd3-scale';
import { Flex } from 'intergalactic/flex-box';
import { Text } from 'intergalactic/typography';
const Demo = () => {
const MARGIN = 40;
const width = 500;
const height = 300;
const xScale = scaleLinear()
.range([MARGIN * 2, width - MARGIN])
.domain([0, 10]);
const yScale = scaleBand()
.range([height - MARGIN, MARGIN])
.domain(data.map((d) => d.category))
.paddingInner(0.4)
.paddingOuter(0.2);
return (
<Plot data={data} scale={[xScale, yScale]} width={width} height={height}>
<YAxis hide={false}>
<YAxis.Ticks />
</YAxis>
<XAxis>
<XAxis.Ticks />
<XAxis.Grid />
</XAxis>
<HoverRect.Tooltip y='category' wMin={100}>
{({ yIndex }) => {
return {
children: (
<>
<HoverRect.Tooltip.Title>{data[yIndex].category}</HoverRect.Tooltip.Title>
<Flex justifyContent='space-between'>
<HoverRect.Tooltip.Dot mr={4}>Bar 1</HoverRect.Tooltip.Dot>
<Text bold>{data[yIndex].bar1}</Text>
</Flex>
<Flex mt={2} justifyContent='space-between'>
<HoverRect.Tooltip.Dot mr={4}>Bar 2</HoverRect.Tooltip.Dot>
<Text bold>{data[yIndex].bar2}</Text>
</Flex>
</>
),
};
}}
</HoverRect.Tooltip>
<GroupBar y='category'>
<GroupBar.HorizontalBar x='bar1' />
<GroupBar.HorizontalBar x='bar2' />
</GroupBar>
</Plot>
);
};
const data = [...Array(5).keys()].map((d, i) => ({
category: `Category ${i}`,
bar1: Math.random() * 10,
bar2: Math.random() * 10,
}));
export default Demo;
Background
Use the <Bar.Background/>
and <HorizontalBar.Background/>
components if you need to add a background to a chart plot.
tsx
import React from 'react';
import { Plot, HorizontalBar, YAxis, XAxis, HoverRect } from 'intergalactic/d3-chart';
import { scaleLinear, scaleBand } from 'd3-scale';
import { Flex } from 'intergalactic/flex-box';
import { Text } from 'intergalactic/typography';
const Demo = () => {
const MARGIN = 40;
const width = 500;
const height = 300;
const xScale = scaleLinear()
.range([MARGIN * 2, width - MARGIN])
.domain([0, 10]);
const yScale = scaleBand()
.range([height - MARGIN, MARGIN])
.domain(data.map((d) => d.category))
.paddingInner(0.4)
.paddingOuter(0.2);
return (
<Plot data={data} scale={[xScale, yScale]} width={width} height={height}>
<YAxis hide={false}>
<YAxis.Ticks />
</YAxis>
<XAxis>
<XAxis.Ticks />
</XAxis>
<HoverRect.Tooltip y='category' wMin={100}>
{({ yIndex }) => {
return {
children: (
<>
<HoverRect.Tooltip.Title>{data[yIndex].category}</HoverRect.Tooltip.Title>
<Flex justifyContent='space-between'>
<HoverRect.Tooltip.Dot mr={4}>Bar</HoverRect.Tooltip.Dot>
<Text bold>{data[yIndex].bar}</Text>
</Flex>
</>
),
};
}}
</HoverRect.Tooltip>
<HorizontalBar x='bar' y='category'>
<HorizontalBar.Background />
</HorizontalBar>
</Plot>
);
};
const data = [...Array(5).keys()].map((d, i) => ({
category: `Category ${i}`,
bar: Math.random() * 10,
}));
export default Demo;
import React from 'react';
import { Plot, HorizontalBar, YAxis, XAxis, HoverRect } from 'intergalactic/d3-chart';
import { scaleLinear, scaleBand } from 'd3-scale';
import { Flex } from 'intergalactic/flex-box';
import { Text } from 'intergalactic/typography';
const Demo = () => {
const MARGIN = 40;
const width = 500;
const height = 300;
const xScale = scaleLinear()
.range([MARGIN * 2, width - MARGIN])
.domain([0, 10]);
const yScale = scaleBand()
.range([height - MARGIN, MARGIN])
.domain(data.map((d) => d.category))
.paddingInner(0.4)
.paddingOuter(0.2);
return (
<Plot data={data} scale={[xScale, yScale]} width={width} height={height}>
<YAxis hide={false}>
<YAxis.Ticks />
</YAxis>
<XAxis>
<XAxis.Ticks />
</XAxis>
<HoverRect.Tooltip y='category' wMin={100}>
{({ yIndex }) => {
return {
children: (
<>
<HoverRect.Tooltip.Title>{data[yIndex].category}</HoverRect.Tooltip.Title>
<Flex justifyContent='space-between'>
<HoverRect.Tooltip.Dot mr={4}>Bar</HoverRect.Tooltip.Dot>
<Text bold>{data[yIndex].bar}</Text>
</Flex>
</>
),
};
}}
</HoverRect.Tooltip>
<HorizontalBar x='bar' y='category'>
<HorizontalBar.Background />
</HorizontalBar>
</Plot>
);
};
const data = [...Array(5).keys()].map((d, i) => ({
category: `Category ${i}`,
bar: Math.random() * 10,
}));
export default Demo;
Legend and pattern fill
Note that for ChartLegend patterns
property works only with default shape={'Checkbox'}
.
tsx
import React from 'react';
import {
Plot,
GroupBar,
YAxis,
XAxis,
HoverRect,
makeDataHintsContainer,
ChartLegend,
} from 'intergalactic/d3-chart';
import { scaleLinear, scaleBand } from 'd3-scale';
import { Flex } from 'intergalactic/flex-box';
import { Text } from 'intergalactic/typography';
const dataHints = makeDataHintsContainer();
const Demo = () => {
const MARGIN = 40;
const width = 500;
const height = 300;
const xScale = scaleLinear()
.range([MARGIN * 2, width - MARGIN])
.domain([0, 10]);
const yScale = scaleBand()
.range([height - MARGIN, MARGIN])
.domain(data.map((d) => d.category))
.paddingInner(0.4)
.paddingOuter(0.2);
const [legendItems, setLegendItems] = React.useState(
Object.keys(data[0])
.filter((name) => name !== 'category')
.map((item, index) => {
return {
id: item,
label: `Bar ${item}`,
checked: true,
color: `chart-palette-order-${index + 1}`,
};
}),
);
const [highlightedLine, setHighlightedLine] = React.useState(-1);
const handleChangeVisible = React.useCallback((id: string, isVisible: boolean) => {
setLegendItems((prevItems) => {
return prevItems.map((item) => {
if (item.id === id) {
item.checked = isVisible;
}
return item;
});
});
}, []);
const handleMouseEnter = React.useCallback((id: string) => {
setHighlightedLine(legendItems.findIndex((line) => line.id === id));
}, []);
const handleMouseLeave = React.useCallback(() => {
setHighlightedLine(-1);
}, []);
return (
<>
<ChartLegend
dataHints={dataHints}
items={legendItems}
onChangeVisibleItem={handleChangeVisible}
onMouseEnterItem={handleMouseEnter}
onMouseLeaveItem={handleMouseLeave}
patterns
/>
<Plot
data={data}
scale={[xScale, yScale]}
width={width}
height={height}
dataHints={dataHints}
patterns
>
<YAxis>
<YAxis.Ticks />
<YAxis.Grid />
</YAxis>
<XAxis>
<XAxis.Ticks />
</XAxis>
<HoverRect.Tooltip y='category' wMin={100}>
{({ yIndex }) => ({
children: (
<>
<HoverRect.Tooltip.Title>{data[yIndex].category}</HoverRect.Tooltip.Title>
<Flex justifyContent='space-between'>
<HoverRect.Tooltip.Dot mr={4} color={legendItems[0].color}>
Bar 1
</HoverRect.Tooltip.Dot>
<Text bold>{data[yIndex][1]}</Text>
</Flex>
<Flex mt={2} justifyContent='space-between'>
<HoverRect.Tooltip.Dot mr={4} color={legendItems[1].color}>
Bar 2
</HoverRect.Tooltip.Dot>
<Text bold>{data[yIndex][2]}</Text>
</Flex>
</>
),
})}
</HoverRect.Tooltip>
<GroupBar y='category'>
{legendItems
.filter((item) => item.checked)
.map((item, index) => {
return (
<GroupBar.HorizontalBar
key={item.id}
x={item.id}
color={item.color}
transparent={highlightedLine !== -1 && highlightedLine !== index}
/>
);
})}
</GroupBar>
</Plot>
</>
);
};
const data = Array(5)
.fill({})
.map((d, i) => ({
category: `Category ${i}`,
1: Math.random() * 10,
2: Math.random() * 10,
}));
export default Demo;
import React from 'react';
import {
Plot,
GroupBar,
YAxis,
XAxis,
HoverRect,
makeDataHintsContainer,
ChartLegend,
} from 'intergalactic/d3-chart';
import { scaleLinear, scaleBand } from 'd3-scale';
import { Flex } from 'intergalactic/flex-box';
import { Text } from 'intergalactic/typography';
const dataHints = makeDataHintsContainer();
const Demo = () => {
const MARGIN = 40;
const width = 500;
const height = 300;
const xScale = scaleLinear()
.range([MARGIN * 2, width - MARGIN])
.domain([0, 10]);
const yScale = scaleBand()
.range([height - MARGIN, MARGIN])
.domain(data.map((d) => d.category))
.paddingInner(0.4)
.paddingOuter(0.2);
const [legendItems, setLegendItems] = React.useState(
Object.keys(data[0])
.filter((name) => name !== 'category')
.map((item, index) => {
return {
id: item,
label: `Bar ${item}`,
checked: true,
color: `chart-palette-order-${index + 1}`,
};
}),
);
const [highlightedLine, setHighlightedLine] = React.useState(-1);
const handleChangeVisible = React.useCallback((id: string, isVisible: boolean) => {
setLegendItems((prevItems) => {
return prevItems.map((item) => {
if (item.id === id) {
item.checked = isVisible;
}
return item;
});
});
}, []);
const handleMouseEnter = React.useCallback((id: string) => {
setHighlightedLine(legendItems.findIndex((line) => line.id === id));
}, []);
const handleMouseLeave = React.useCallback(() => {
setHighlightedLine(-1);
}, []);
return (
<>
<ChartLegend
dataHints={dataHints}
items={legendItems}
onChangeVisibleItem={handleChangeVisible}
onMouseEnterItem={handleMouseEnter}
onMouseLeaveItem={handleMouseLeave}
patterns
/>
<Plot
data={data}
scale={[xScale, yScale]}
width={width}
height={height}
dataHints={dataHints}
patterns
>
<YAxis>
<YAxis.Ticks />
<YAxis.Grid />
</YAxis>
<XAxis>
<XAxis.Ticks />
</XAxis>
<HoverRect.Tooltip y='category' wMin={100}>
{({ yIndex }) => ({
children: (
<>
<HoverRect.Tooltip.Title>{data[yIndex].category}</HoverRect.Tooltip.Title>
<Flex justifyContent='space-between'>
<HoverRect.Tooltip.Dot mr={4} color={legendItems[0].color}>
Bar 1
</HoverRect.Tooltip.Dot>
<Text bold>{data[yIndex][1]}</Text>
</Flex>
<Flex mt={2} justifyContent='space-between'>
<HoverRect.Tooltip.Dot mr={4} color={legendItems[1].color}>
Bar 2
</HoverRect.Tooltip.Dot>
<Text bold>{data[yIndex][2]}</Text>
</Flex>
</>
),
})}
</HoverRect.Tooltip>
<GroupBar y='category'>
{legendItems
.filter((item) => item.checked)
.map((item, index) => {
return (
<GroupBar.HorizontalBar
key={item.id}
x={item.id}
color={item.color}
transparent={highlightedLine !== -1 && highlightedLine !== index}
/>
);
})}
</GroupBar>
</Plot>
</>
);
};
const data = Array(5)
.fill({})
.map((d, i) => ({
category: `Category ${i}`,
1: Math.random() * 10,
2: Math.random() * 10,
}));
export default Demo;