d3 v5绘制简单的折线图,并使用promise映射/投射到数字 [英] d3 v5 plotting simple line chart and mapping/casting to numbers using promise

查看:96
本文介绍了d3 v5绘制简单的折线图,并使用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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆