【问题标题】:Bars not plotted in D3 stacked bar chart条形图未在 D3 堆积条形图中绘制
【发布时间】:2021-12-13 06:04:50
【问题描述】:

我使用 d3 构建了一个堆积图。但是第一个数据被绘制,但第二个数据没有被绘制。数据是从 API 中获取的,数字可能会有很大的不同。在第一个数据中,E 未绘制在图表中,并且条形超过 Y 轴的高度。而且,第二个根本没有绘制。如何解决这个问题。我检查了几个示例,我认为我遵循的代码是相同的。我不知道出了什么问题。

另外,我在这里给出了一个固定的条形尺寸。条不是在中心绘制,而是向左绘制。我需要将每个条形图绘制在中间。

代码,

const data = [
{'category': 'Type 1', A: 0, B: 1402574577, C: 0, D: 19197208547, E: 1792937}, {category: 'Type 2', A: 14600000, B: 0, C: 0, D: 0, E: 2369530}]
const keys = ['A', 'B', 'C', 'D', 'E']
const cost = [
    [0, 1402574577, 0 , 19197208547, 1792937],
    [14600000, 0, 0, 0, 2369530]
]

const width = 500;
const height = 300;
const margin = {left: 100, top: 60, right: 60};

let svg = d3
      .select('#stackedbars')
      .append('svg')
      .attr('width', width + margin.left + margin.right)
      .attr('height', height + margin.top * 2)
      .style('background', '#fff');
      
svg = svg.append('g')
      .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

const xScaleRange = data.length * 120;

const x = d3.scaleBand()
         .rangeRound([0, xScaleRange])
         .padding(0.1)
         
const y = d3.scaleLinear()
          .range([height, 0]);
  
const z = d3.scaleOrdinal()
          .domain(keys)
          .range(["#F6D7A7", "#F6EABE", "#C8E3D4", "#87AAAA", "#247291"]);
x.domain(data.map(d => d.category));
y.domain([0, d3.max(cost.flat())]).nice()

const gX = svg.append('g')
  .attr('class', 'axis')
  .attr('transform', `translate(0,${height})`)
  .call(d3.axisBottom(x).tickSizeOuter(0))
  .call(g => g.selectAll('.tick > line')
  .filter((d, i, nodes) => i < nodes.length - 1)
  .clone()
  .attr('stroke', '#cccccc')
  .attr('x1', x.step() / 2)
  .attr('x2', x.step() / 2)
  .attr('y1', -height)
  .attr('y2', 0));

const gY = svg.append('g')
  .attr('class', 'axis')
  .call(d3.axisLeft(y).ticks(null, 's').tickFormat(d => d))
  .call(g => g.selectAll('.tick > line')
  .filter((d, i) => i > 0)
  .clone()
  .attr('stroke', '#cccccc')
  .attr('x1', 0)
  .attr('x2', width));

gX.selectAll("line")
  .style("stroke", "#eeeeee");

gX.selectAll("path")
  .style("stroke", "#eeeeee");

gY.selectAll("line")
  .style("stroke", "#eeeeee");

gY.selectAll("path")
  .style("stroke", "#eeeeee");

gY.selectAll("text")
  .style("fill", "#8a8a8a");
  
const dataStackLayout = d3.stack().keys(keys)(data);
const layer = svg.selectAll(".stack")
    .data(dataStackLayout)
    .enter().append("g")
    .attr("class", "stack")
    .style("fill",  (d) => {
      return z(d.key)
    });

layer.selectAll("rect")
  .data(d => d)
  .enter().append("rect")
  .attr("x", d => {
    return x(d.data.category)
  })
  .attr("y",  d => y(d[1]))
  .attr("height", d => y(d[0]) - y(d[1]))
  .attr("width", "25")

【问题讨论】:

    标签: javascript d3.js


    【解决方案1】:

    您的代码基本上是正确的。问题在于价值观和尺度。参见 sn-p 中的示例:

    const data = [
    {'category': 'Type 1', A: 10, B: 20, C: 30, D: 40, E: 50}, {category: 'Type 2', A: 50, B: 40, C: 30, D: 20, E: 10}]
    const keys = ['A', 'B', 'C', 'D', 'E']
    const colors = {
     'A': 'red',
     'B': 'green',
     'C': 'blue',
     'D': 'yellow',
     'E': 'orange'
    };
    
    const width = 500;
    const height = 300;
    const margin = {left: 100, top: 60, right: 60};
    
    let svg = d3
          .select('#stackedbars')
          .append('svg')
          .attr('width', width + margin.left + margin.right)
          .attr('height', height + margin.top * 2)
          .style('background', '#fff');
          
    svg = svg.append('g')
          .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
    
    const xScaleRange = data.length * 120;
    
    const x = d3.scaleBand()
             .rangeRound([0, xScaleRange])
             .padding(0.1)
             
    const y = d3.scaleLinear()
                        .domain([0, 200])
              .range([height, 0]);
    
    x.domain(data.map(d => d.category));
    
    const gX = svg.append('g')
      .attr('class', 'axis')
      .attr('transform', `translate(0,${height})`)
      .call(d3.axisBottom(x).tickSizeOuter(0))
      .call(g => g.selectAll('.tick > line')
      .filter((d, i, nodes) => i < nodes.length - 1)
      .clone()
      .attr('stroke', '#cccccc')
      .attr('x1', x.step() / 2)
      .attr('x2', x.step() / 2)
      .attr('y1', -height)
      .attr('y2', 0));
    
    const gY = svg.append('g')
      .attr('class', 'axis')
      .call(d3.axisLeft(y).ticks(null, 's').tickFormat(d => d))
      .call(g => g.selectAll('.tick > line')
      .filter((d, i) => i > 0)
      .clone()
      .attr('stroke', '#cccccc')
      .attr('x1', 0)
      .attr('x2', width));
    
    gX.selectAll("line")
      .style("stroke", "#eeeeee");
    
    gX.selectAll("path")
      .style("stroke", "#eeeeee");
    
    gY.selectAll("line")
      .style("stroke", "#eeeeee");
    
    gY.selectAll("path")
      .style("stroke", "#eeeeee");
    
    gY.selectAll("text")
      .style("fill", "#8a8a8a");
      
    const dataStackLayout = d3.stack().keys(keys)(data);
    const layer = svg.selectAll(".stack")
        .data(dataStackLayout)
        .enter().append("g")
        .attr("class", "stack")
        .style("fill",  (d) => {
          return colors[d.key]
        });
    
    layer.selectAll("rect")
      .data(d => d)
      .enter().append("rect")
      .attr("x", d => {
        return x(d.data.category) + 35
      })
      .attr("y",  d => y(d[1]))
      .attr("height", d => y(d[0]) - y(d[1]))
      .attr("width", 30)
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    <div id="stackedbars" />

    【讨论】:

      猜你喜欢
      • 2021-10-28
      • 2016-10-13
      • 1970-01-01
      • 2012-09-17
      • 2021-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多