简体   繁体   中英

d3 area stacked line chart

I'm working on modifying this stacked line chart example: https://bl.ocks.org/d3indepth/e4efd402b4d9fdb2088ccdf3135745c3

I'm adding a time x axis, but I'm struggling with this block of code:

var areaGenerator = d3.area()
  .x(function(d, i) {
      // return i * 100;
      return i * 253.5;
  })
  .y0(function(d) {
      return y(d[0]);
  })
  .y1(function(d) {
      return y(d[1]);
  });

The original example has the .x accessor as i * 100 which seems to be a random value. When I add the X axis the stacked line chart does not line up correctly with the date ticks. I can manually force it to line up by returning i * 253.5 but that is not ideal. I don't really understand how this area function is working - any help would be appreciated.

 let height = 600; let width = 800; const yMax = 4000; //var hEach = 40; let margin = {top: 20, right: 15, bottom: 25, left: 25}; width = width - margin.left - margin.right; height = height - margin.top - margin.bottom; var svg = d3.select('body').append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); let formatDate = d3.timeFormat("%b-%Y") let parseTime = d3.timeParse("%Y-%m-%d"); let data = [ { "host_count": 2553, "container_count": 875, "hour": "2019-01-31", "apm_host_count": 0, "agent_host_count": 2208, "gcp_host_count": 0, "aws_host_count": 345 }, { "host_count": 1553, "container_count": 675, "hour": "2019-02-01", "apm_host_count": 0, "agent_host_count": 1208, "gcp_host_count": 0, "aws_host_count": 445 }, { "host_count": 716, "container_count": 6234, "hour": "2019-02-02", "apm_host_count": 0, "agent_host_count": 479, "gcp_host_count": 0, "aws_host_count": 237 }, { "host_count": 516, "container_count": 4234, "hour": "2019-02-03", "apm_host_count": 0, "agent_host_count": 679, "gcp_host_count": 0, "aws_host_count": 137 } ]; // format the data data.forEach(function(d) { d.hour = parseTime(d.hour); }); // set the ranges var x = d3.scaleTime().range([0, width]); x.domain(d3.extent(data, function(d) { return d.hour; })); var xAxis = d3.axisBottom(x).ticks(11).tickFormat(d3.timeFormat("%y-%b-%d")).tickValues(data.map(d=>d.hour)); var y = d3.scaleLinear() .domain([0, yMax]) .range([height, 0]); var areaGenerator = d3.area() .x(function(d, i) { console.log(d); return i * 100; }) .y0(function(d) { return y(d[0]); }) .y1(function(d) { return y(d[1]); }); var colors = ['#FBB65B', '#513551', '#de3163'] var stack = d3.stack() .keys(['agent_host_count', 'aws_host_count', 'container_count']); var stackedSeries = stack(data); d3.select('g') .selectAll('path') .data(stackedSeries) .enter() .append('path') .style('fill', function(d, i) { return colors[i]; }) .attr('d', areaGenerator) svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis);
 <!doctype html> <html lang="en"> <head> <title>Usage</title> </head> <body> <div id="svg"></div> <script src="https://d3js.org/d3.v5.min.js"></script> </body> </html>

When using axes in d3, you actually need to use the axis variable to calculate scaling factors. The functions that do this calculation are returned by the scale*() methods. In your code you have this for the x-axis:

  var x = d3.scaleTime().range([0, width]);

As such, the variable x now contains a function that will do interpolation for you. this is what your areaGenerator function should look like:

var areaGenerator = d3.area()
  .x(function(d, i) {
      return x(d.data.hour);
  })
  .y0(function(d) {
      return y(d[0]);
  })
  .y1(function(d) {
      return y(d[1]);
  });

The only thing you need to remember is that when calculating the value you need to use the same variable that the axis is based on. Ie your x-axis is a time axis so you need to calculate the interpolation using the time variable ( d.data.hour ).

As to where 100 comes from in the example, you are essentially correct. In that block the value of 100 is more or less arbitrary. It was likely chosen because the chart looks reasonably good at that scale. By choosing 100, each "tick" is spaced 100px apart and since there is no x-axis to be judged against it doesn't actually matter what is used as long as it changes for each data point.

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