... может ли d3 помочь мне с чем-то специальным образом получить правильное значение y?
Нет, для этого нет собственного метода. Но здесь большинство людей ошибаются в D3: D3 - это не инструмент построения диаграмм (за исключением модуля оси, D3 ничего не рисует!), Это просто набор методов JavaScript. Этот факт одновременно дает D3 его слабость (крутая кривая обучения) и его преимущество (с D3 вы можете сделать почти все).
В вашем случае, например, все, что я хотел бы сделать, это разделить данные в бункерах (используя генератор гистограмм, например, или просто напрямую манипулируя данными), а затем добавляя кружки в каждую ячейку / группу, используя их индексы .
Это может быть что-то вроде этого:
circle.attr("cy", function(_, i) {
return maxValue - circleRadius * i;
});
Это добавит первый кружок каждого бина (группы) в основании SVG, а затем каждый последующий в меньшую y
координату, в соответствии с его индексом.
Проверьте это основное демо:
const data = d3.range(100).map(() => Math.random());
const svg = d3.select("svg");
const xScale = d3.scalePoint(d3.range(10).map(d => d / 10), [20, 480])
.padding(0.5);
const binData = d3.histogram()
.domain([0, 1])(data);
const g = svg.selectAll(null)
.data(binData)
.enter()
.append("g")
.attr("transform", d => "translate(" + xScale(~~(100 * d.x0) / 100) + ",0)");
g.selectAll(null)
.data(d => d)
.enter()
.append("circle")
.attr("r", 5)
.attr("cy", function(_, i) {
return 220 - 13 * i;
})
.style("fill", "gray")
.style("stroke", "black");
const axisGroup = svg.append("g")
.attr("transform", "translate(0,230)")
.call(d3.axisBottom(xScale));
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="500" height="250"></svg>