I'm trying to plot some numbers on the y axis that correspond to strings on the x axis using d3.js version 7. I'm not sure what x scale to use. I'm trying scaleOrdinal but the plot is not correct. I'd like the strings evenly spaced on the x axis with a little padding on the ends.
const data = [{str: 'a', num: 1}, {str: 'b', num: 3}, {str: 'c', num: 2}, {str: 'd', num: 0}];
const svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
const xScale = d3.scaleOrdinal()
.domain(d3.extent(data, function (d) {
return d.str;
}))
.range([0, width]);
var yScale = d3.scaleLinear()
.domain([0, 5])
.range([height, 0]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale))
.style('color', '#80ffffff')
.style('font-size', 20)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em");
svg.append("g")
.call(d3.axisLeft(yScale))
.style('color', '#80ffffff');
const valueline = d3.line()
.x(function (d) {
return xScale(d.str);
})
.y(function (d) {
return yScale(d.num);
});
svg.append("path")
.data([data])
.attr("class", "line")
.attr("d", valueline)
.style("fill", "none")
.style("stroke", '#ff0000ff')
.style("stroke-width", 1);
The ordinal scale is not the correct one here, mainly because ordinal scales need to have discrete (i.e. qualitative, categorical) domain and range.
What you want is a point scale. Also, pay attention to the fact that d3.extent only returns 2 values (in your case "a" and "d"), so what you want is a regular Array.prototype.map. That said, your scale is:
const xScale = d3.scalePoint()
.domain(data.map(function (d) {
return d.str;
}))
.range([0, width])
.padding(yourPaddingHere)