У меня есть гистограмма с накоплением, и мне нужно добавить интервалы и нарисовать линии на оси X после определенных c точек.
Пока это то, что я достиг, что почти точно что мне нужно (это скриншот бегущего графика):
Единственный способ, которым я смог найти создание линий и промежутков между ними Bars должен был создавать новые категории (называемые ими внутренне «separatorX») со значением 0, а затем скрывать его метку, когда он содержит слово «разделитель», но это выглядит очень странно.
Моя конечная цель состоит в том, чтобы найти более элегантный способ добавить дополнительное поле или интервал для указанных c точек оси X, поэтому не нужно создавать новые и ненужные пустые категории. Кроме того, я хотел бы настроить значение поля / интервала для каждой точки, чтобы не все они занимали одно и то же пространство.
Это фрагмент структуры данных, которая у меня есть прямо сейчас:
const data = [
{"phase":"0","total":1887,"subphase1":100,"subphase2":523,"subphase3":397,"subphase4":593,"subphase5":274},
{"phase":"1","total":2367,"subphase1":100,"subphase2":402,"subphase3":649,"subphase4":723,"subphase5":493},
{"phase":"2","total":1883,"subphase1":100,"subphase2":623,"subphase3":278,"subphase4":552,"subphase5":330},
{"phase":"3","total":1744,"subphase1":100,"subphase2":174,"subphase3":827,"subphase4":379,"subphase5":264},
{"phase":"separator1","total":0,"subphase1":0,"subphase2":0,"subphase3":0,"subphase4":0,"subphase5":0},
{"phase":"5","total":2414,"subphase1":100,"subphase2":727,"subphase3":406,"subphase4":362,"subphase5":819},
{"phase":"6","total":2124,"subphase1":100,"subphase2":607,"subphase3":434,"subphase4":619,"subphase5":364},
{"phase":"separator2","total":0,"subphase1":0,"subphase2":0,"subphase3":0,"subphase4":0,"subphase5":0},
{"phase":"separator3","total":0,"subphase1":0,"subphase2":0,"subphase3":0,"subphase4":0,"subphase5":0},
{"phase":"9","total":1643,"subphase1":100,"subphase2":303,"subphase3":256,"subphase4":779,"subphase5":205},
{"phase":"10","total":2213,"subphase1":100,"subphase2":643,"subphase3":778,"subphase4":486,"subphase5":206}
...
]
И это функция, в которой я определяю xScale (что, я думаю, именно там может произойти исправление):
const xScale = d3
.scaleBand(
data.map(d => d.phase),
[margin.left, width - margin.right]
)
.padding(0.5);
Заранее спасибо всем, кто читает это! Любая помощь будет принята с благодарностью !!!
Вот вам пример:
const data = this.props.data;
const width = 700;
const height = 500;
const margin = {
top: 10,
right: 0,
bottom: 60,
left: 42
};
const barWidth = 12;
const containerBarWidth = barWidth + 16;
// Specific
const barColors = [Colors.TUNDORA, Colors.SILVER_CHALICE, Colors.SAN_MARINO, Colors.VIKING, Colors.SHAMROCK];
const colors = d3.scaleOrdinal(data.categories, barColors);
// Scales
const xScale = d3
.scaleBand(
data.map(d => d.phase),
[margin.left, width - margin.right]
)
.padding(0.5);
const yScale = d3.scaleLinear(
[0, d3.max(data, d => d.total + d.total * 0.1)],
[height - margin.bottom, margin.top + 55]
);
// Axis
const xAxis = d3.axisBottom(xScale);
const yAxis = d3.axisLeft(yScale).ticks(4);
// Data preparation
const stack = d3.stack().keys(data.categories);
const chartData = stack(data);
// SVG
const svg = d3
.select(this._rootNode)
.append("svg")
.attr("width", width)
.attr("height", height);
// Bars
const groups = svg
.append("g")
.selectAll("g")
.data(chartData)
.join("g")
.style("fill", (d, i) => colors(d.key));
groups
.selectAll("rect")
.data(d => d)
.join("rect")
.attr("x", d => xScale(d.data.phase))
.attr("y", d => yScale(d[1]))
.attr("height", d => yScale(d[0]) - yScale(d[1]))
.attr("width", d => barWidth)
.attr("stroke", "white")
.attr("stroke-width", 2);
let separators = ["separator1", "separator3", "separator4", "separator6", "separator7"];
separators.forEach(separator => {
const line = svg
.append("g")
.attr(
"transform",
"translate(" + (xScale(separator) - xScale.step() * xScale.padding() * 0.5 + 16) + ", 0)"
);
line.append("line")
.attr("y1", margin.top)
.attr("y2", height - margin.bottom)
.style("stroke", Colors.ALTO)
.style("shape-rendering", "crispEdges");
});
let groupTitlesAnchors = [
{ anchor: "0", title: "Group 1 >" },
{ anchor: "5", title: "Group 2 >" },
{ anchor: "9", title: "Group 3 >" },
{ anchor: "13", title: "Group 4 >" },
{ anchor: "17", title: "Group 5 >" },
{ anchor: "22", title: "Group 6 >" }
];
groupTitlesAnchors.forEach(group => {
const point = svg
.append("g")
.style("font", "12px Arial")
.attr("transform", "translate(" + (xScale(group.anchor) - xScale.step() + 10) + ", 36)");
point
.append("text")
.text(group.title)
.style("user-select", "none")
.attr("x", 20);
});
// Axis
svg.append("g")
.style("font", "12px Arial")
.attr("transform", `translate(0,${height - margin.bottom})`)
.attr("class", "xAxis")
.call(
xAxis.tickFormat((d, i) => {
return d.includes("separator") ? `separator${i}` : i;
})
)
.selectAll("text")
.attr("y", 6)
.attr("x", 6)
.attr("transform", "rotate(45)")
.style("text-anchor", "start");
svg.append("g")
.style("font", "12px Arial")
.attr("transform", `translate(${margin.left}, -1)`)
.attr("class", "yAxis")
.call(yAxis);
// Groups/Labels top separator
svg.append("line")
.style("stroke", Colors.ALTO)
.attr("x1", margin.left)
.attr("y1", margin.top + 43)
.attr("x2", width)
.attr("y2", margin.top + 43)
.style("shape-rendering", "crispEdges");
// Borders
svg.append("line")
.style("stroke", Colors.ALTO)
.attr("x1", margin.left)
.attr("y1", margin.top + 1)
.attr("x2", width)
.attr("y2", margin.top + 1)
.style("shape-rendering", "crispEdges");
svg.append("line")
.style("stroke", Colors.ALTO)
.attr("x1", width)
.attr("y1", margin.top)
.attr("x2", width)
.attr("y2", height - margin.bottom)
.style("shape-rendering", "crispEdges");
svg.append("line")
.style("stroke", Colors.ALTO)
.attr("x1", margin.left)
.attr("y1", margin.top)
.attr("x2", margin.left)
.attr("y2", height - margin.bottom - 1)
.style("shape-rendering", "crispEdges");
svg.append("line")
.style("stroke", Colors.ALTO)
.attr("x1", margin.left)
.attr("y1", height - margin.bottom)
.attr("x2", width)
.attr("y2", height - margin.bottom)
.style("shape-rendering", "crispEdges");