javascript - D3 中使用内部 JSON 变量的堆叠条形图

标签 javascript json d3.js

因此尝试在 D3.js 中创建堆叠条形图。我已经让轴工作了,但是图表数据没有显示,有什么想法我哪里出错了吗?

JS:

var svg = d3.select("#recovery__table"),
    margin = {top: 20, right: 20, bottom: 30, left: 40},
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom,
    aspect = width/height,
    g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var x = d3.scaleBand()
    .rangeRound([0, width])
    .padding(0.1)
    .align(0.1);

var y = d3.scaleLinear()
    .rangeRound([height, 0]);

var z = d3.scaleOrdinal()
    .range(["#717C8B", "#7FDDC3", "#39B3CD"]);

var stack = d3.stack();

data.forEach(function(d) {
    d.year = d['trades.closed_half_year_year'];
    d.loss = d['loss'];
    d.recovered = d['recovered'];
    d.recovery = d['in_recovery'];
    d.total = d.loss + d.recovery + d.recovered;
});

var div = d3.select("body").append("div")
    .attr("class", "tooltip3")
    .style("opacity", "0");

 x.domain(data.map(function(d) { return d.year; }));
 y.domain([0, d3.max(data, function(d) { return d.total; })]).nice();
 z.domain(d3.keys(data[0]).filter(function(key){ return key == 'loss' && key == 'recovered' && key == 'in_recovery' }));

 g.selectAll(".serie")
      .data(data)
      .enter().append("rect")
      .attr("class", "bar")
      .attr("fill", function(d){ return z(d.keys); })
      .attr("x", function(d) { return x(d.year); })
      .attr("width", x.bandwidth())
      .attr("y", function(d) { return y(d.total); })
      .attr("height", function(d) { return y[0] - y[1]; })
      .on("mouseover", function(d) {
        var value = parseInt($(this).attr('data-value'));
        div.transition()
          .duration(200)
          .style("opacity", .5);
        div.html(d.data.year + "<br/>£" + total.formatMoney())
          .style("left", (d3.event.pageX) + "px")
          .style("top", (d3.event.pageY - 28) + "px");
      })
      .on("mouseout", function(d) {
        div.transition()
          .duration(500)
          .style("opacity", 0);
      });
    ;

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

 g.append("g")
      .attr("class", "axis axis--y")
      .call(d3.axisLeft(y).ticks(5, "s"))
      .append("text")
      .attr("x", 2)
      .attr("y", y(y.ticks(10).pop()))
      .attr("dy", "0.35em")
      .attr("text-anchor", "start")
      .attr("fill", "#000");

 var legend = g.selectAll(".legend")
      .data(data)
      .enter().append("g")
      .attr('width', 100)
      .attr("class", "legend")
      .attr('transform', function(d, i) {
        var horz = 100*i;                       // NEW
        var vert = 0;
        if (horz >= width) {
          horz = 100 * (i - 3);
          vert = 40;
        }

        return 'translate(' + horz + ',' + vert + ')';        // NEW
      })
      .style("font", "10px sans-serif");

 legend.append("rect")
      .attr("x", "33%")
      .attr("width", 18)
      .attr("height", 18)
      .attr("fill", z);

 legend.append("text")
      .attr("x", "43%")
      .attr("y", 9)
      .attr("dy", ".35em")
      .attr("text-anchor", "end")
      .text(function(d) { return d; });

JSON 示例

[{"trades.closed_half_year_year":"2017","auctioncollectioninfos.total_advanced_amount_delinquent_and_collection_completed_gbp_daily":"£0.00","auctioncollectioninfos.total_crystallized_loss_gbp_daily":"£0.00","auctioncollectioninfos.total_outstanding_amount_delinquent_gbp_daily":"£","auctioncollectioninfos.total_advanced_amount_delinquent_gbp_daily":"£0.00","loss":"£0.00","recovered":"£0.00","in_recovery":"£0"},
{"trades.closed_half_year_year":"2016","auctioncollectioninfos.total_advanced_amount_delinquent_and_collection_completed_gbp_daily":"£123,456.78","auctioncollectioninfos.total_crystallized_loss_gbp_daily":"£0.00","auctioncollectioninfos.total_outstanding_amount_delinquent_gbp_daily":"£1,234,234","auctioncollectioninfos.total_advanced_amount_delinquent_gbp_daily":"£1,321,245.56","loss":"£0.00","recovered":"£457,468.31","in_recovery":"£1,890,567"},
{"trades.closed_half_year_year":"2015","auctioncollectioninfos.total_advanced_amount_delinquent_and_collection_completed_gbp_daily":"£3,345,768.54","auctioncollectioninfos.total_crystallized_loss_gbp_daily":"£555,555.08","auctioncollectioninfos.total_outstanding_amount_delinquent_gbp_daily":"£321,321","auctioncollectioninfos.total_advanced_amount_delinquent_gbp_daily":"£3,321,321.32","loss":"£456,324.33","recovered":"£2,324,234.345","in_recovery":"£333,333"}]

本质上,需要将丢失、恢复和恢复堆栈到图表上,但如前所述,没有数据加载到图表上。

有什么想法吗?

最佳答案

有一个小问题,您使用的数据是 JSON,因此对象将以字符串形式接收值,您必须将它们正确解析为数字。将字符串解析为数字的简单方法如下:

d.loss = +d['loss'];

但即使我们这样做了,您的数据仍然会出现问题。为什么?因为数据集中的某些数字已格式化:

"loss":"£456,324.33" 

所以如果你想尝试做这样的事情:

d.total = d.loss + d.in_recovery + d.recovered;

您将得到一个无效值,因为我们可能会发出如下所示的操作:

d.total = "£456,324.33" + 0 + "£4,324.33"  // "£456,324.330£4,324.33"

这将改变我们图表中的尺度。

y.domain([0, d3.max(data, function(d) {
   return d.total;
})]).nice(); // spooky domain here :S

让我们处理值的格式(假设值始终按照您提供的 JSON 中呈现的方式进行格式化):

data.forEach(function(d) {
  d.year = +d['trades.closed_half_year_year'];
  d.loss = typeof d.loss === 'number' ? d.loss : +d['loss'].replace(/£|,/g, '')
  d.recovered = typeof d.recovered === 'number' ? d.recovered : +d['recovered'].replace(/£|,/g, '');
  d.in_recovery = typeof d.in_recovery === 'number' ? d.in_recovery : +d['in_recovery'].replace(/£|,/g, '');
  d.total = d.loss + d.in_recovery + d.recovered;
});

现在我们有了正确的数据集,我们应该准备好开始使用 d3 和 stack 布局:

var keys = ['loss', 'recovered', 'in_recovery']; // Declare the keys we will want in our stack
z.domain(keys); // Set them as our z domain so we can retrieve our fill color
var stackLayout = d3.stack().keys(keys)(data); // Create our stack layout

这将创建以下结构:

[
   [
      [
         0,
         0
      ],
      [
         0,
         0
      ],
      [
         0,
         456324.33
      ]
      // key: loss
   ],
   [
      [
         0,
         0
      ],
      [
         0,
         457468.31
      ],
      [
         456324.33,
         2780558.6750000003
      ]
      // key: recovered
   ],
   [
      [
         0,
         0
      ],
      [
         457468.31,
         2348035.31
      ],
      [
         2780558.6750000003,
         3113891.6750000003
      ]
      // key: in_recovery
   ]
]

通过上面的结构,我们现在可以通过键 block 创建条形,如您所见,每个数组都有三个值和一个键。我们需要为每个数组元素创建一个 group 元素:

g.selectAll(".serie")
  .data(stackLayout) // Set stack layout as data
  .enter()
  .append("g") // Creating group for each key
  .attr("fill", function(d) { return z(d.key); }) // Fill inner elements with the color provided by our z Scale
  .selectAll("rect") 
  .data(function(d) { // Use the inner array to create our rects
    return d;
  })
  .enter().append("rect")
  .attr("x", function(d) { // Position by our x Scale
    return x(d.data.year);
  })
  .attr("y", function(d) { // Position by our y Scale
    return y(d[1]);
  })
  .attr("height", function(d) { // Find the height value by using the values provided in the inner arrays
    return y(d[0]) - y(d[1]);
  })
  .attr("width", x.bandwidth()); 

我们还必须更改一些标签:

var legend = g.selectAll(".legend")
  .data(keys.reverse()) // Use our keys
  .enter().append("g")
  .attr("class", "legend")
  .attr('transform', function(d, i) {
    var horz = width - margin.right - (100 * i); // NEW
    var vert = 0;
    return 'translate(' + horz + ',' + vert + ')'; // NEW
  })
  .style("font", "10px sans-serif");

legend.append("text")
  .attr("x", "-5")
  .attr("y", 9)
  .attr("dy", ".35em")
  .attr("text-anchor", "end")
  .text(function(d) {
    return d;
  });

工作 plnkr:https://plnkr.co/edit/eTKsOz8jlaqm1Mf3Esej?p=preview

关于javascript - D3 中使用内部 JSON 变量的堆叠条形图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42397138/

相关文章:

javascript - 在 D3.js 中过滤 CSV 的多行并更新键盘输入的过滤器

javascript - 如何在鼠标悬停时获取直方图中数据元素的索引?

javascript - 使用 d3.js 图表填充页面时的 CSS/对齐问题

javascript - 如何防止 flex 容器溢出/下溢?

javascript - 在 Javascript 中如何制作具有可实例化的自定义行为的数组?

java - 如何使用 Spring Boot 和 AngularJS 将 JSON 对象插入数据库?

JSONPath 从嵌套 json 中获取多个值

php - 从 php 中的文件夹中读取文件并列出 json 文件中的条目

javascript - React Native timemixin 取消定时器超时

javascript - 输入具有起始值和结束值的双范围值