I'm trying to create a grouped bar chart by city with 3 category, however it is only draws one group and all others are taking the same position so they are on top of each other. It doesn't take the whole width and doesn't spread along x scale. Something wrong with my x0 and x1 scales. If I understand correctly x0 is the beginning and x1 scale is the end position of rectangles in the chart? Can you explain what am I doing wrong here?
Here's a snippet of the problem:
const groupedBarChartData = {
dataset: [
{
City: 'York',
'Sales': 20000,
'Returns': 25000,
'Total': 22000,
},
{
City: 'London',
'Sales': 40000,
'Returns': 43000,
'Total': 45000,
},
{
City: 'Manchester',
'Sales': 40000,
'Returns': 7000,
'Total': 19999,
}]}
// svg dimensions
const width = 1192;
const height = 610;
const colorScale = d3
.scaleOrdinal()
.range(['red', 'blue', 'green', 'orange']);
const svg = d3.select('body').append('svg');
// shape data
const data = groupedBarChartData.dataset;
// get categories
const keys = Object.keys(data[0]).slice(1);
// x axis
const x0Scale = d3.scaleBand().rangeRound([0, width]);
const x1Scale = d3.scaleBand();
// set x0 - cities
x0Scale.domain(data.map((d) => d['City']));
// set x1 - categories
x1Scale.domain(keys).rangeRound([0, x0Scale.bandwidth()]);
// y axis
const yScale = d3.scaleLinear().range([height, 0]);
// equal to Math.round(data.map((x) => Math.max(...keys.map((el) => x[el]))).sort((a, b) => b - a)[0])
yScale.domain([
0,
Math.round(d3.max(data, (d) => d3.max(keys, (key) => d[key]))),
]);
// draw chart
svg
.selectAll('rect')
.data(data)
.enter()
.selectAll('rect')
.data((d) =>
keys.map((key) => {
return { key: key, value: d[key] };
})
)
.enter()
.append('rect')
.attr('x', (d, i) => x1Scale(d.key))
.attr('y', (d) => yScale(d.value))
.attr('width', x1Scale.bandwidth() - 15)
.attr('height', (d) => height - yScale(d.value))
.attr('fill', (d) => colorScale(d.key));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
And the result it gives me:
