在 D3.js 中创建分类折线图 (V4)
Creating a categorical line chart in D3.js (V4)
我 相对 是 D3.js 的新手,我正在可视化我的 中的 'PassengersIn' 和 'PassengersOut' 值]busdatasimple.json 文件。作为参考,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 没有缩放到我的数据。如下所示;
我的代码如下。我删除了不相关的 Google 地图和 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 中,您拥有全新的 scaleBand
和 scalePoint
.
在 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);
我 相对 是 D3.js 的新手,我正在可视化我的 中的 'PassengersIn' 和 'PassengersOut' 值]busdatasimple.json 文件。作为参考,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 没有缩放到我的数据。如下所示;
我的代码如下。我删除了不相关的 Google 地图和 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 中,您拥有全新的 scaleBand
和 scalePoint
.
在 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);