【问题标题】:How to plot stacked bar chart according to the custom Y axis in D3如何根据D3中的自定义Y轴绘制堆积条形图
【发布时间】:2020-08-25 22:21:37
【问题描述】:

我有一个堆积条形图,我必须在 0 到 100 之间显示数据百分比。 例如 - 如果 a、b 的值是 3、10 中的 7,那么我必须将其显示为 30% 和 70%。但有时数据会低于 1%,所以我将 Y 轴修改为如下所示,它是均匀分布的,但无法根据自定义 Y 轴放置图表。

custom Yaxis chart

这就是我使用 D3 修改 Y 轴的方式

var y_data = [0,1,2,3,4,5,6,7,8,9,10,30,50,70,100];

var y = d3.scaleLinear()
  .domain([0, 100])
  .range([height, 0])
  svg.append("g").attr('class', 'y-stack')
  .call(d3.axisLeft(y).tickValues(y_data).tickSize(10).tickPadding(10));

d3.select('.y-stack').selectAll('.tick').each(function(i, val) {
  const temp_height = height + margin.top + margin.bottom - margin.left;
  const diff = temp_height / (y_data.length - 1);
  $(<any>this).attr('transform', 'translate(0, ' + (temp_height - (diff * val ) + 0.5 + ')'));
});

现在我该如何绘制图表,或者有什么简单的方法可以代替为它制作自定义计算函数。

【问题讨论】:

    标签: javascript d3.js


    【解决方案1】:

    您可以通过提供n 域值(您提供的y_ticks)和n 范围值(沿轴从0 开始的像素数)的数组来做到这一点。然后它还会自动插入例如 15,使其在 10 到 30 之间达到 25%。

    我从here获得了基本代码:

    var data = [{
        "State": "AL",
        "Under 5 Years": 52,
        "5 to 13 Years": 29,
        "14 to 17 Years": 10
      },
      {
        "State": "AK",
        "Under 5 Years": 56,
        "5 to 13 Years": 21,
        "14 to 17 Years": 20
      },
      {
        "State": "AZ",
        "Under 5 Years": 28,
        "5 to 13 Years": 62,
        "14 to 17 Years": 15
      },
      {
        "State": "AR",
        "Under 5 Years": 43,
        "5 to 13 Years": 17,
        "14 to 17 Years": 20
      },
      {
        "State": "CA",
        "Under 5 Years": 49,
        "5 to 13 Years": 15,
        "14 to 17 Years": 30
      },
      {
        "State": "CO",
        "Under 5 Years": 87,
        "5 to 13 Years": 1,
        "14 to 17 Years": 11
      }
    ];
    
    var keys = Object.keys(data[0]).slice(2);
    var states = [...new Set(data.map(d => d.State))]
    var yTicks = [0,1,2,3,4,5,6,7,8,9,10,30,50,70,100];
    
    function getRange(from, to) {
      const interpolator = d3.interpolate(from, to);
      return new Array(yTicks.length)
        .fill(undefined)
        .map((_, i) => interpolator(i / yTicks.length));
    }
    
    var svg = d3.select("#chart"),
      margin = {
        top: 35,
        left: 35,
        bottom: 0,
        right: 0
      },
      width = +svg.attr("width") - margin.left - margin.right,
      height = +svg.attr("height") - margin.top - margin.bottom;
    
    var x = d3.scaleBand()
      .range([margin.left, width - margin.right])
      .padding(0.1)
    
    var y = d3.scaleLinear()
      .range(getRange(height - margin.bottom, margin.top))
      .domain(yTicks)
    
    var xAxis = svg.append("g")
      .attr("transform", `translate(0,${height - margin.bottom})`)
      .attr("class", "x-axis")
    
    var yAxis = svg.append("g")
      .attr("transform", `translate(${margin.left},0)`)
      .attr("class", "y-axis")
    
    var z = d3.scaleOrdinal()
      .range(["steelblue", "darkorange", "lightblue"])
      .domain(keys);
    
    data.forEach(function(d) {
      d.total = d3.sum(keys, k => +d[k])
      return d
    });
    
    svg.selectAll(".y-axis")
      .call(d3.axisLeft(y).tickValues(yTicks))
    
    data.sort((a, b) => states.indexOf(a.State) - states.indexOf(b.State))
    
    x.domain(data.map(d => d.State));
    
    svg.selectAll(".x-axis")
      .call(d3.axisBottom(x).tickSizeOuter(0))
    
    var group = svg.selectAll("g.layer")
      .data(d3.stack().keys(keys)(data), d => d.key)
    
    group.exit().remove()
    
    group.enter().append("g")
      .classed("layer", true)
      .attr("fill", d => z(d.key));
    
    var bars = svg.selectAll("g.layer").selectAll("rect")
      .data(d => d, e => e.data.State);
    
    bars.exit().remove()
    
    bars.enter().append("rect")
      .attr("width", x.bandwidth())
      .merge(bars)
      .attr("x", d => x(d.data.State))
      .attr("y", d => y(d[1]))
      .attr("height", d => y(d[0]) - y(d[1]))
    
    var text = svg.selectAll(".text")
      .data(data, d => d.State);
    
    text.exit().remove()
    
    text.enter().append("text")
      .attr("class", "text")
      .attr("text-anchor", "middle")
      .merge(text)
      .attr("x", d => x(d.State) + x.bandwidth() / 2)
      .attr("y", d => y(d.total) - 5)
      .text(d => d.total)
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.js"></script>
    <svg id="chart" width="650" height="400"></svg>

    【讨论】:

      猜你喜欢
      • 2021-12-13
      • 1970-01-01
      • 1970-01-01
      • 2020-12-27
      • 1970-01-01
      • 1970-01-01
      • 2018-06-05
      • 1970-01-01
      • 2012-09-17
      相关资源
      最近更新 更多