在d3v4堆叠条形图中使用JSON

时间:2018-07-27 21:43:36

标签: javascript json d3.js dataset bar-chart

我找到了我想使用的d3v3 stacked bar chart example,因为它使用json数据。

还有一个d3v4 canonical bar chart example可以加载和使用csv。

我想制作一个d3v4堆叠的条形图,但我想使用json数据创建它,而不是从csv加载。我不确定如何升级v3版本或修改v4版本来实现此目的。

这是我的数据结构:

[{
     "hospitalName": "hospital1",
     "category": "Injury & Poisoning",        
     "Females": "0",
     "Males": "4",
     "Unknown": "0",
     "count": "4"
},
{
    "hospitalName": "hospital1",
    "category": "Symptoms, Signs, & Ill-Defined Conditions",
    "Females": "1",
    "Males": "1",
    "Unknown": "0",
    "count": "2"
},
{
    "hospitalName": "hospital2",
    "category": "Mental Disorders",
    "Females": "0",
    "Males": "1",
    "Unknown": "0",
    "count": "1"
}]

在给出两个示例的情况下,如何在d3v4堆叠条形图中使用此数据?

1 个答案:

答案 0 :(得分:2)

考虑到在升级适合您的数据源类型的v3示例和修改v4示例以使用json而不是csv数据之间的选择,应该选择转换现有的规范v4示例。

d3.csv将csv文件转换为json。 d3.csv从源csv创建的头文件看起来与您的json一样,其头文件等于您的数据项的属性。 因此,两个示例实质上都使用相同的数据格式和结构。这就是为什么使用d3v4示例更直接的原因。

要使用json数据而不是v4示例中的csv数据,您需要进行两项更改:

  1. 获取正确的列数据:

规范中的列使用var keys = data.columns.slice(1);来获取csv数据中应使用矩形绘制的列。 columns是d3.csv添加到数据数组的属性,用于指定列标题。删除的值不是用矩形绘制的,而是标识堆栈,它可以是堆栈标签,并用于x轴放置。由于d3.csv添加了columns属性,因此我们需要一种略有不同的方法。

在您的情况下,看起来我们想从数据中获取男性,女性,未知人物,并且每个组的结构如下:

{
     "hospitalName": "hospital1",
     "category": "Injury & Poisoning",        
     "Females": "0",
     "Males": "4",
     "Unknown": "0",
     "count": "4"
}

因此,我们可以对键/属性(将用矩形绘制)进行一些修改:

var columns = d3.keys(data[0]);  // get the properties of the first item in the data array
var keys = columns.slice(2,5); // extract keys with index 2,3,4. These will be the properties that are represented by rectangles in the chart.
  1. 说明多个具有相同名称的组/堆栈

由于大多数示例的比例尺将使用组名,因此这些将不起作用。取而代之的是,我们每个组都需要唯一的东西,索引可以正常工作:

x.domain(data.map(function(d,i) { return i; }));

您需要对刻度线进行一些格式化,以免将索引作为标签,让我们说:

d3.axisBottom(x).tickFormat(function(d,i) { return data[i].hospitalName })

使用该类别将价格添加到刻度线应该足够容易。

  1. 修改总属性

是的,我说了两个步骤,这太短了,不足以保证整个项目符号,但是列出三个项目会更好。原始规范使用d.total,您的数据使用d.count,这用于确定y标度的域。

一起:

<!DOCTYPE html>
<style>

.axis .domain {
  display: none;
}

</style>
<svg width="600" height="200"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>

var svg = d3.select("svg"),
    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,
    g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

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

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

var z = d3.scaleOrdinal()
    .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);

  var data = [{
     "hospitalName": "hospital1",
     "category": "Injury & Poisoning",        
     "Females": "0",
     "Males": "4",
     "Unknown": "0",
     "count": "4"
},
{
    "hospitalName": "hospital1",
    "category": "Symptoms, Signs, & Ill-Defined Conditions",
    "Females": "1",
    "Males": "1",
    "Unknown": "0",
    "count": "2"
},
{
    "hospitalName": "hospital2",
    "category": "Mental Disorders",
    "Females": "0",
    "Males": "1",
    "Unknown": "0",
    "count": "1"
}]
	
	var columns = d3.keys(data[0]);

  var keys = columns.slice(2,5);

  data.sort(function(a, b) { return b.total - a.total; });
  x.domain(data.map(function(d,i) { return i; }));
  y.domain([0, d3.max(data, function(d) { return d.count; })]).nice();
  z.domain(keys);

  g.append("g")
    .selectAll("g")
    .data(d3.stack().keys(keys)(data))
    .enter().append("g")
      .attr("fill", function(d) { return z(d.key); })
    .selectAll("rect")
    .data(function(d) { return d; })
    .enter().append("rect")
      .attr("x", function(d,i) { return x(i); })
      .attr("y", function(d) { return y(d[1]); })
      .attr("height", function(d) { return y(d[0]) - y(d[1]); })
      .attr("width", x.bandwidth());

  g.append("g")
      .attr("class", "axis")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(x).tickFormat(function(d,i) { return data[i].hospitalName}));

  g.append("g")
      .attr("class", "axis")
      .call(d3.axisLeft(y).ticks(null, "s"))
    .append("text")
      .attr("x", 2)
      .attr("y", y(y.ticks().pop()) + 0.5)
      .attr("dy", "0.32em")
      .attr("fill", "#000")
      .attr("font-weight", "bold")
      .attr("text-anchor", "start")
      .text("Population");

  var legend = g.append("g")
      .attr("font-family", "sans-serif")
      .attr("font-size", 10)
      .attr("text-anchor", "end")
    .selectAll("g")
    .data(keys.slice().reverse())
    .enter().append("g")
      .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });

  legend.append("rect")
      .attr("x", width - 19)
      .attr("width", 19)
      .attr("height", 19)
      .attr("fill", z);

  legend.append("text")
      .attr("x", width - 24)
      .attr("y", 9.5)
      .attr("dy", "0.32em")
      .text(function(d) { return d; });


</script>

如果要使用d3.json,则可以使用:

d3.json("json.json", function(error,data) {
  if(error) throw error;

  // Parts that use the data here.

})