d3 v5绘制简单的折线图,并使用promise映射/投射到数字 [英] d3 v5 plotting simple line chart and mapping/casting to numbers using promise
问题描述
在使用v3多年之后,我终于决定放弃并采用d3 v5语法.看了一些教程和示例之后,v5语法确实让我赞叹不已.可读性大大提高,并且似乎更容易集成多个数据源.
I have finally decided to saddle up and adopt d3 v5 syntax after years of using v3. After looking at some tutorials and examples, v5 syntax really struck me as sublime. The readability is far improved and it seems easier to integrate multiple data sources.
令我沮丧的是,尽管我敬畏它,但我还是不能完全使用新的 Promise
语法从头开始构建视觉效果.这是我的简单图形:(请注意,出于本文的目的,我正在使用硬编码数据,并且已经注释掉了我实际使用的 .csv()
调用.它仍然在功能上相同)
To my dismay, and despite my reverence of it, I couldn't quite build a visual from scratch with the new Promise
syntax. Here is my simple graph: (note I'm using hard coded data for the sake of this post, and I have commented out the .csv()
call that I'd actually use. It should still be functionally the same)
var margins = {top:50, right:50, bottom:50, left:50};
var width = window.innerWidth - margins.left - margins.right;
var height = window.innerHeight - margins.top - margins.bottom;
var sampleData = [
{'y':32, 'x':1},
{'y':20, 'x':2},
{'y':19, 'x':3},
{'y':12, 'x':4},
{'y':15, 'x':5},
{'y':19, 'x':6},
{'y':22, 'x':7},
{'y':26, 'x':8},
{'y':31, 'x':9},
{'y':36, 'x':10}
];
//var dataset = d3.csv("my-data.csv").then(function(data)
// {return data;
// });
var dataset = sampleData.then(function(data)
{return data;
});
var svg = d3.select('body').append('svg').attr('id','svg').attr('height','100%').attr('width','100%');
var myLine = dataset.then(function(data) {
Promise.all(data.map(function(d) {return {X:+d.x, Y:+d.y}}))//ensure numeric parsing
var xScale = d3.scaleLinear()
.domain(d3.extent(data, function(d) { return d.X; }))
.range([0,width]);
var yScale = d3.scaleLinear()
.domain(d3.extent(data, function(d) {return d.Y; }))
.range([height,0]);
var xAxis = d3.axisBottom(xScale);
var yAxis = d3.axisLeft(yScale);
var line = d3.line()
.x(function(d) {return xScale(d.x); })
.y(function(d) {return yScale(d.y); });
var svg = d3.select('body').append('svg').attr('id','svg').attr('height','100%').attr('width','100%');
var graphGroup = svg.append('g')
.attr('transform',"translate("+margins.left+","+margins.top+")");
graphGroup.append('path')
.attr('d', function(d) {return line(data); });
graphGroup.append('g')
.attr('class', 'axis x')
.attr('transform', "translate(0,"+height+")")
.call(xAxis);
graphgroup.append('g')
.attr('class', 'axis y')
.call(yAxis);
});
我在控制台中收到此错误:
I get this error in the console:
未捕获的TypeError:sampleData.则不是函数
Uncaught TypeError: sampleData.then is not a function
问题
我认为 Promise.all()
和 .then()
并不总是对真正简单的数据可视化有利,但我仍然想知道为什么我不能使上面的脚本输出最小的折线图.从那时起,希望我可以慢慢地卸下训练轮,并在v5上大步向前.
Question
I take the point that Promise.all()
and .then()
are not always favorable for really simple data visuals, but I'd still like to know why I can't make the above script output a minimal line graph. From then, hopefully, I can slowly take the training wheels off and find my stride with v5.
我特别困惑如何使用带有Promise的一元 +
转换为数字.
I'm particularly confused with how to cast to numbers using the unary +
with Promise.
推荐答案
尽管在使用Promises时有很多曲折,但事实证明,要使用 d3-fetch 模块,建议使用已弃用的
Although there are many twists and turns when it comes to using Promises, it turns out that the actual changes required to port code to make use of the d3-fetch module in favor of the deprecated d3-request module are strikingly minimal. Loosely speaking, to adapt your—or any pre-v5—code to use the new d3-fetch module you just move the callback from one method to another. Thus, the former
d3.dsv(url, callback);
现在成为
d3.dsv(url).then(callback);
唯一需要注意的是检查回调的签名是否与 .then
所期望的签名匹配.但是,只有在您的回调使用两个参数来处理错误时,这才有意义:
The only thing to be aware of is to check if the callback's signature matches the one expected for .then
. This only becomes relevant, though, if your callback used two parameters to handle errors:
function callback(error, data) {
// Handle error
if (error) throw error;
// Manipulate data
}
使用Promises可以将其分为两个单独的方法:
With Promises this is split into two separated methods:
function onFullfilled(data) {
// Manipulate data
}
function onRejected(error) {
// Handle error
}
这些回调可以通过两种方式使用:
These callback can be used in two ways:
// 1.
d3.dsv(url).then(onFullfilled, onRejected);
// 2.
d3.dsv(url).then(onFullfilled).catch(onRejected);
另一个重要的一点是,您不能从回调中返回数据(请注意臭名昭著的 如何从异步调用返回响应?" !). d3.dsv
现在返回一个Promise,而不是您的数据;您必须处理回调中的数据.如果您更加熟练地使用Promises,则可以查看浏览器支持.
Another important point is that you cannot return data from your callback (beware of the infamous "How do I return the response from an asynchronous call?"!). d3.dsv
now returns a Promise, not your data; you have to handle the data inside your callback. If you become more skilled using Promises you might have a look into the await
operator, though, which allows you to wait for a Promise and its fulfilled value. Although this is ECMAScript 2017 (ES8) syntax it has already seen wide-spread browser support.
这是一般情况,现在对于您的代码: sampleData
是一个 Array
对象,它当然没有 .then()
方法,因此会出现错误.要使代码正常工作,除了取消注释带有 d3.dsv
的行并将注释中的相关代码处理数据放入
That being the general case, now for your code: sampleData
is an Array
object which, of course, does not have a .then()
method and, hence, the error. To make the code work there is not much to do apart from uncommenting the lines featuring d3.dsv
and putting the relevant code handling data inside the callback.
If you really want to do an offline simulation with hardcoded data you can use Promise.resolve()
which will return a Promise already resolved with the given value. In your case instead of
d3.csv("my-data.csv")
.then(function(data) { });
您可以使用
Promise.resolve(sampleDate)
.then(function(data) { }); // Same handler as above
这篇关于d3 v5绘制简单的折线图,并使用promise映射/投射到数字的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!