简体   繁体   中英

Draw vertical line after n data points in d3

I have a graph drawn with d3 with the x and y scales defined as follows:

x = d3.scaleLinear().domain([30, 150]).range([0, width])
y = d3.scaleLinear().domain([0, 100]).range([height, 0])

I need to draw a vertical line after 25% of data points. So I have my code like this:

svg.append('line')
  .attr('x1', lowerLimit)
  .attr('y1', 0)
  .attr('x2', lowerLimit)
  .attr('y2', height)
  .style('stroke', 'red')

My problem is I am not sure how to set the lowerLimit x value to be 25% of all the x-values in the scale. Can someone help please? Thanks in advance!

Well, your question is not clear. When you say:

I need to draw a vertical line after 25% of data points

You're talking about the first quartile , which is impossible to calculate without the data, and not only that, but which changes for every different data set.

If you are indeed talking about the first quartile, this is what you have to do:

Given an data array called data , you can use d3.quantile :

var firstQuartile = d3.quantile(data, 0.25);

In the following demo, I'm plotting 100 dots, and calculating the 25 percentile (first quartile) regarding the property x :

var lowerLimit = d3.quantile(data, 0.25, function(d) {
    return d.x
});

The console shows the value. Check the demo:

 var data = d3.range(100).map(() => ({ x: Math.random() * 120 + 30, y: Math.random() * 100 })); var w = 500, h = 160; var svg = d3.select("body") .append("svg") .attr("width", w) .attr("height", h); x = d3.scaleLinear().domain([30, 150]).range([20, w - 20]); y = d3.scaleLinear().domain([0, 100]).range([h - 20, 20]); var xAxis = d3.axisBottom(x); var yAxis = d3.axisLeft(y); var circles = svg.selectAll("circles") .data(data) .enter() .append("circle") .attr("r", 2) .attr("fill", "teal") .attr("cx", d => x(dx)) .attr("cy", d => y(dy)); var data = data.sort((a, b) => d3.ascending(ax, bx)) var lowerLimit = d3.quantile(data, 0.25, function(d) { return dx }); console.log(lowerLimit); svg.append('line') .attr('x1', x(lowerLimit)) .attr('y1', 20) .attr('x2', x(lowerLimit)) .attr('y2', h - 20) .style('stroke', 'red') svg.append("g") .attr("transform", "translate(0," + (h - 20) + ")") .call(xAxis); svg.append("g") .attr("transform", "translate(20,0)") .call(yAxis); 
 <script src="https://d3js.org/d3.v4.min.js"></script> 

However, if you're talking about "getting the value that is 25% of the domain" , the answer is easy. You can, for instance, create a function:

function findLimit(percentage) {
    return x(x.domain()[0] + (x.domain()[1] - x.domain()[0]) * percentage / 100);
};

And pass the value of that function to lowerLimit :

var lowerLimit = findLimit(25);

Check this demo, drawing a line at 25% of the x axis:

 var data = d3.range(100).map(() => ({ x: Math.random() * 120 + 30, y: Math.random() * 100 })); var w = 500, h = 200; var svg = d3.select("body") .append("svg") .attr("width", w) .attr("height", h); x = d3.scaleLinear().domain([30, 150]).range([20, w - 20]); y = d3.scaleLinear().domain([0, 100]).range([h - 20, 20]); var xAxis = d3.axisBottom(x); var yAxis = d3.axisLeft(y); var circles = svg.selectAll("circles") .data(data) .enter() .append("circle") .attr("r", 2) .attr("fill", "teal") .attr("cx", d => x(dx)) .attr("cy", d => y(dy)); var data = data.sort((a, b) => d3.ascending(ax, bx)) var lowerLimit = d3.quantile(data, 0.25, function(d) { return dx }); console.log(lowerLimit); svg.append('line') .attr('x1', x(lowerLimit)) .attr('y1', 20) .attr('x2', x(lowerLimit)) .attr('y2', h - 20) .style('stroke', 'red') svg.append("g") .attr("transform", "translate(0," + (h - 20) + ")") .call(xAxis); svg.append("g") .attr("transform", "translate(20,0)") .call(yAxis); 
 <script src="https://d3js.org/d3.v4.min.js"></script> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM