直方图绘制箱中的极值

时间:2021-01-02 03:47:29

标签: javascript d3.js data-science data-visualization histogram

我试图在直方图中绘制值,但在某些情况下,我无法处理极端值,例如正确绘制了 1,2,25,35,23,60 之类的值,但 1,23 之类的值, 45、60、1000、45000 是如此遥远,以至于 xScale 将域视为 (1, 4500),然后绘制的值非常遥远。有什么办法可以将最后一个元素组合在一起?由于我使用相同的 xScale 域,因此对于此直方图,也以类似的方式生成 bin,如下所述

  histogram = d3
            .histogram()
            .value((d) => d.value)
            .domain(xScale.domain())
            .thresholds(xScale.ticks(threshold));

  bins = histogram(data)

基本上我在这里想的是我需要调整 xScale 的域(如果我是对的)以使垃圾箱正确。我想得到类似 >100 的值,然后结合 1000 和 4500 的最后两个值,然后在考虑上述情况的情况下绘制在同一条上。

1 个答案:

答案 0 :(得分:0)

这样的事情怎么样:

<!DOCTYPE html>

<html>
  <head>
    <script src="https://d3js.org/d3.v6.min.js"></script>
  </head>

  <body>
    <svg></svg>
    <script>
      // set up normal graph
      var margin = {
          top: 20,
          right: 20,
          bottom: 30,
          left: 50,
        },
        width = 600 - margin.left - margin.right,
        height = 300 - margin.top - margin.bottom;

      // our bin size will be segments of 10
      // with a max of 100
      // anything over 100 will be binned together
      var binSize = 10,
          binLimit = 100;

      // some fake data, 100 points < 100
      // 10 points possibly > 100
      var data = d3
        .range(100)
        .map(() => {
          return { value: Math.random() * binLimit };
        })
        .concat(
          d3.range(10).map(() => {
            return { value: Math.random() * 5000 };
          })
        );

      // max value in data set
      var maxValue = d3.max(data, (d) => {
        return d.value;
      });

      // set the parameters for the histogram
      var histogram = d3
        .histogram()
        .value((d) => {
          return d.value;
        })
        .domain([0, maxValue])
        // thresholds would be [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
        // so anything >100 will be binned at end
        .thresholds(d3.range(0,110,10));

      var bins = histogram(data);

      var x = d3.scaleLinear()
        .range([0, width])
        // set our scale to have a domain with two extra increments at the end
        .domain([0, binLimit + (binSize * 2)]);

      // set up svg object
      var svg = d3
        .select('svg')
        .attr('width', width + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
        .append('g')
        .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

      // add x-axis
      svg
        .append('g')
        .attr('transform', 'translate(0,' + height + ')')
        .attr('class', 'x-axis')
        .call(d3.axisBottom(x));

      // y-axis
      var y = d3.scaleLinear().range([height, 0]);
      y.domain([
        0,
        d3.max(bins, function (d) {
          return d.length;
        }),
      ]);

      svg.append('g').call(d3.axisLeft(y));

      var bWidth = x(bins[0].x1) - x(bins[0].x0) - 1

      // append our rects
      svg
        .selectAll('rect')
        .data(bins)
        .enter()
        .append('rect')
        .attr('x', 1)
        .attr('transform', function (d) {
          if (d.x1 > 100){
            // if this is the last bin
            // place it in our special column on the end
            return 'translate(' + x(binLimit + binSize) + ',' + y(d.length) + ')';
          } else {
            return 'translate(' + x(d.x0) + ',' + y(d.length) + ')';
          }
        })
        .attr('width', bWidth)
        .attr('height', function (d) {
          return height - y(d.length);
        })
        .style('fill', '#69b3a2');

      // modify last two labels
      document.querySelector('.x-axis .tick:nth-last-child(2)')
        .children[1].innerHTML = '>100';
      document.querySelector('.x-axis .tick:nth-last-child(1)')
        .children[1].innerHTML = '<5000';

    </script>
  </body>
</html>