我绘制了一个多折线图,该图根据某些用户输入而变化。我想添加一条参考线以始终出现在值 y=100 处。我能够手动放置一条线,但它并不总是恰好在 y=100。
撇开格式问题不谈,这就是我对一个可能的用户输入的看法。如您所见,参考线略低于 100:
还有我的代码:
const svg = d3.select("svg");
const width = +svg2.attr("width");
const height = +svg2.attr("height");
const render = data =>{
const xValue = d => +d.week;
const yValue = d => +d.power_score;
const margin = {top:50, right:70, bottom:60, left:20};
const innerWidth = width - margin.left - margin.right;
const innerHeight = height - margin.top - margin.bottom;
const colorValue = d => d.team;
// define scales
const xScale = d3.scaleLinear()
.domain([1, d3.max(data, xValue)])
.range([0, innerWidth-250])
.nice();
const yScale = d3.scaleLinear()
.domain([d3.min(data, yValue)-10, d3.max(data, yValue)+10])
.range([innerHeight, 0])
.nice();
const colorScale = d3.scaleOrdinal(d3.schemeCategory10);
const g = svg2.append("g")
.attr('transform', 'translate(75, 50)');
// create axes
const xAxis = d3.axisBottom(xScale)
.tickSize(-innerHeight-10);
const yAxis = d3.axisLeft(yScale)
.tickSize(-innerWidth+240);
const xAxisG = g.append("g").call(xAxis)
.attr("transform", "translate(0, 400)");
xAxisG.select(".domain")
.remove();
xAxisG.append("text")
.attr("class", "axis-label")
.attr("y", 40)
.attr("x", (innerWidth-250)/2)
.attr("fill", "black")
.text("Week");
const yAxisG = g.append("g").call(yAxis)
.attr("transform", "translate(-10, 0)")
.select(".domain")
.remove();
yAxisG.append("text")
.attr("class", "axis-label")
.attr("transform", "rotate(-90)")
.attr("y", -35)
.attr("x", -innerHeight/4)
.attr("fill", "black")
.text("Power Score");
// generate line
const lineGenerator = d3.line()
.x(d => xScale(xValue(d)))
.y(d => yScale(yValue(d)));
// sort data for legend
const lastYValue = d =>
yValue(d.values[d.values.length - 1]);
// group data
const nested = d3.nest()
.key(colorValue)
.entries(data)
.sort((a, b) =>
d3.descending(lastYValue(a), lastYValue(b)));
colorScale.domain(nested.map(d => d.key));
// manually add horizonal line here
svg2.append("g")
.attr("transform", "translate(75, 267)")
.append("line")
.attr("x2", innerWidth-250)
.style("stroke", "black")
.style("stroke-width", "2px")
.style("stroke-dasharray", "3, 3");
// add lines with mouseover effect
g.selectAll(".line-path").data(nested)
.enter().append("path")
.attr("class", "line-path")
.attr("d", d => lineGenerator(d.values))
.attr("stroke", d => colorScale(d.key))
.attr("stroke-width", "3")
.attr("opacity", "0.5")
.on("mouseover", function(d, i) {
d3.select(this).transition()
.duration("50")
.attr("stroke-width", "5")
.attr("opacity", "1")})
.on("mouseout", function(d, i) {
d3.select(this).transition()
.duration("50")
.attr("stroke-width", "3")
.attr("opacity", "0.5")});
d3.line()
.x(d => xScale(xValue(d)))
.y(d => yScale(yValue(d)));
// draw legend
const colorLegend = (selection, props) => {
const {
colorScale,
circleRadius,
spacing,
textOffset
} = props;
const groups = selection.selectAll('g')
.data(colorScale.domain());
const groupsEnter = groups
.enter().append('g')
.attr('class', 'tick');
groupsEnter
.merge(groups)
.attr('transform', (d, i) =>
`translate(0, ${i * spacing})`
);
groups.exit().remove();
groupsEnter.append('circle')
.merge(groups.select('circle'))
.attr('r', circleRadius)
.attr('fill', colorScale);
groupsEnter.append('text')
.merge(groups.select('text'))
.text(d => d)
.attr('dy', '0.32em')
.attr('x', textOffset);
}
svg2.append("g")
.attr("transform", "translate(710, 60)")
.call(colorLegend, {
colorScale,
circleRadius: 4,
spacing: 15,
textOffset: 8
});
// Title
g.append("text")
.attr("class", "title")
.attr("x", (innerWidth-250)/4)
.attr("y", -10)
.text("Weekly Power Ranks");
};
d3.csv('data.csv').then(data => {
data.forEach(d => {
d.week = +d.week;
d.power_score = +d.power_score;
});
render(data);
});
答案 0 :(得分:1)
而不是使用幻数...
svg2.append("g")
.attr("transform", "translate(75, 267)")
//magic numbers---------------^----^
...使用与绘制路径相同的 y 比例:
g.append("g")
.attr("transform", `translate(75, ${yScale(100)})`)
此外,将其附加到已翻译的 <g>
,或应用相同的翻译(同样,在您的代码中添加更多幻数......)。