I am creating a stacked bar chart in d3.js, and I am having a few problems. My chart looks like this (created in D3.js):
but it should look something like this (created with Observable.Plot):
How can I change my code to:
- Show the bars on the X axis in the correct location
- change the height of each bar to be accurate
- change the color of each bar to accurately show the proper data
- What can i put as the "width" of each bar since the width is dynamic (the date range can change externally to this function)
If my data is not structured correctly, please let me know. I'm not sure if it is getting stacked correctly by d3.stack();
Initial Data: (unnecessary data points are blacked out for simplicity)
This is the same data after stacking:
with each array having:
This is my stack function:
const stack: any = d3
.stack()
.keys(services) // string[]
.value((x) => x.count); // count is a number
var data = stack(props.data);
console.log(props.data); // initial data array (as shown)
console.log(data); // data array after stacking (as shown)
Scales:
// x axis time scale
const xAxisScale_min: Date = d3.min(props.data.map((i) => i.createdDate))!;
const xAxisScale_max: Date = d3.max(props.data.map((i) => i.createdDate))!;
const x = d3
.scaleTime()
.domain([xAxisScale_min, xAxisScale_max])
.range([0, WIDTH]);
const yAxisScale_max: any = 10;
// y axis scale
const y = d3.scaleLinear().domain([0, yAxisScale_max]).range([HEIGHT, 0]);
And this is the code creating each rect
const rects = g.selectAll("rects").data(data);
var color = d3.scaleOrdinal(services, d3.schemeCategory10);
svg
.append("g")
.selectAll("g")
// Enter in the stack data = loop key per key = group per group
.data(data)
.enter()
.append("g")
.attr("fill", function (d: any) {
return color(d.key);
})
.selectAll("rect")
// enter a second time = loop subgroup per subgroup to add all rectangles
.data(function (d): any {
return d;
})
.enter()
.append("rect")
.attr("x", function (d: any) {
return x(new Date(d.data.createdDate));
})
.attr("y", function (d: any) {
return y(d[1]);
})
.attr("height", function (d: any) {
return y(d[0]) - y(d[1]);
})
.attr("width", WIDTH / props.data.length);
If you need the x and y axes grid information I can show that too, but I omitted it for simplicity.