I drew a multi-line chart that changes based on some user input. I want to add a reference line to always appear at the value y=100. I was able to manually place a line, but it is not always exactly at y=100.
Formatting issues aside, this is what I have for one possible user input. As you can see, the reference line is slightly below 100:
And my code:
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); }); https://stackoverflow.com/questions/66522754/add-constant-horizontal-line March 08, 2021 at 07:56AM

没有评论:
发表评论