javascript - 在 D3.js (V4) 中创建分类折线图

标签 javascript json d3.js linechart

相对是 D3.js 的新手,我正在可视化我的 busdatasimple.json 文件中的“PassengersIn”和“PassengersOut”值。作为引用,其中一个 JSON 对象如下所示;

  {
    "BusNo": "1",
    "Date": "21 November 2016",
    "Time": "09:10:34 AM",
    "Destination": "Pier 50",
    "Longitude": "-122.383262",
    "Latitude": "37.773644",
    "PassengersIn": "8",
    "PassengersOut": "1"
  }

我现在尝试使用折线图上的两条线绘制 PassengersIn 和 PassengersOut 与 Destination 的关系图。我在轴上苦苦挣扎,因为 x 只有 2 个刻度,而 y 没有缩放到我的数据。如下所示; Line Graph with ordinal scale

我的代码如下。我删除了不相关的 Google map 和 jQuery。

//Setting The Dimensions Of The Canvas
var margin = {top: 20, right: 20, bottom: 70, left: 40},
    width = 650 - margin.left - margin.right,
    height = 350 - margin.top - margin.bottom;

//Setting X & Y Ranges
var x = d3.scaleOrdinal().range([0, width]);
var y = d3.scaleLinear().range([height, 0]);

//Define The Axes
var xAxis = d3.axisBottom().scale(x);
var yAxis = d3.axisLeft().scale(y).ticks(10);

//Add The SVG Element
var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right + 50)
    .attr("height", height + margin.top + margin.bottom + 200)
    .attr("class", "svg")
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

//Load Data From JSON
d3.json("busdatasimple.json", function(error, data) {
  //Functions for Y-Axis Grid Lines
  function yGridLines() {
    return d3.axisLeft().scale(y).ticks(5);
  }

  //Adding the Y-Axis Grid Lines
  svg.append("g")
      .attr("class", "grid-lines")
      .call(yGridLines().tickSize(-width, 0, 0).tickFormat(""));

  //Adding Y-Axis
  svg.append("g")
      .attr("class", "y axis").call(yAxis)
    .append("text")
      .attr("transform", "rotate(-90)")
      .attr("y", 5)
      .attr("dy", ".71em")
      .style("text-anchor", "end")
      .text("Passengers In");
  
   //Adding X-Axis (Added to the end of the code so the label show over bottom bars)
   svg.append("g")
     .attr("class", "x axis")
     .attr("transform", "translate(0," + height + ")")
     .call(xAxis)
   .selectAll("text")
     .style("text-anchor", "middle")
     //.attr("dx", "-.8em")
     .attr("dy", "-.55em")
     .attr("transform", "translate(-5, 15)")
     .attr("font-family", "Arial")
     .attr("font-weight", "bold")
     .attr("font-size", "1.1em");

    x.domain(data.map(function(d){return d.Destination;}));
    y.domain([d3.min(data, function(d){return d.PassengersIn;}), d3.max(data, function(d)     {return d.PassengersIn;})]);

    var line = d3.line()
      .x(function(d){return x(d.Destination);})
      .y(function(d){return y(d.PassengersIn);});

    svg.append("path").datum(data)
      .attr("class", "line")
      .attr("d", function(d){return d.PassengersIn;})
      .attr("stroke", "green")
      .attr("stroke-width", 2);
});

我设法找到了一些使用分类序数尺度的示例,但是,它们都使用了 d3.js 的 v3,并且在无数次阅读了 v4 API 之后,我仍然无法弄明白。

最佳答案

你想要一个分类尺度,这是正确的,但你不想要一个序数尺度

从 v3 到 v4 有很多变化。在 v3 中,您可以将 .rangeBands、.rangeRoundBands、.rangePoints 和 .rangeRoundPoints 设置为您的序数比例,因此可以接受连续范围。不再是:在 D3 v4 中,您拥有全新的 scaleBandscalePoint

在 v4 中,以常规序数比例(即 scaleOrdinal):

If range is specified, sets the range of the ordinal scale to the specified array of values. The first element in the domain will be mapped to the first element in range, the second domain value to the second range value, and so on. If there are fewer elements in the range than in the domain, the scale will reuse values from the start of the range. (emphases mine)

因此,在 scaleOrdinal 中,范围需要与域的长度(元素数)相同。

话虽这么说,但您需要一个点比例尺 (scalePoint)。带刻度和点刻度...

...are like ordinal scales except the output range is continuous and numeric. (emphasis mine)

检查此代码段,查看控制台并比较两个比例:

var destinations = ["foo", "bar", "baz", "foobar", "foobaz"];

var scale1 = d3.scaleOrdinal()
	.range([0, 100])
	.domain(destinations);
	
var scale2 = d3.scalePoint()
	.range([0, 100])
	.domain(destinations);
	
destinations.forEach(d=>{
console.log(d + " in an ordinal scale: " + scale1(d) + " / in a point scale: " + scale2(d))
})
<script src="https://d3js.org/d3.v4.min.js"></script>

关于您的 y 轴问题:

调用轴之前设置 y 尺度的域。所以,而不是这个:

svg.append("g")
    .attr("class", "y axis").call(yAxis);

y.domain([d3.min(data, function(d){
    return d.PassengersIn;
}), d3.max(data, function(d){
    return d.PassengersIn;
})]);

改变顺序:

y.domain([d3.min(data, function(d){
    return d.PassengersIn;
}), d3.max(data, function(d){
    return d.PassengersIn;
})]);//set the domain first!

svg.append("g")
    .attr("class", "y axis").call(yAxis);

关于javascript - 在 D3.js (V4) 中创建分类折线图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41426884/

相关文章:

javascript - 如何从 JSON 数组中获取特定数据?

d3.js - D3 单调插值 - 平滑直线

javascript - Canvas 中的 Onclick 监听器

javascript - 在 Javascript 中交换数组元素

javascript - 无需 jQuery 即可链接具有父/子关系的复选框

javascript - json 数组中的项目数

javascript - 通过引用传递对象时 $OnChange 不会触发

javascript - AngularJS ng-style转义变量中的非法字符

javascript - 在 D3-Tip 中创建 HTML 元素触发点击事件

javascript - 使用基于 d3.js 的图表库