【问题标题】:d3 array input line graph exampled3数组输入折线图示例
【发布时间】:2014-02-22 16:46:20
【问题描述】:

我对 d3 很陌生,为了了解我正在尝试操纵 d3.js line example,代码如下。我正在尝试修改它以使用我手头已有的模型数据。此数据作为 json 对象向下传递。问题是我不知道如何操纵数据以适应 d3 的期望。大多数 d3 示例使用键值数组。我想使用一个键数组+一个值数组。例如,我的数据按照以下示例进行结构化:

// my data. A name property, with array values and a value property with array values.
// data is the json object returned from the server
var tl   = new Object;
tl.date  = data[0].fields.date;
tl.close = data[0].fields.close;
console.log(tl);

这是视觉上的结构(是的,现在是时间格式):

现在这与 data.tsv 调用不同,后者在下面的代码中生成键值对。

目标是按原样使用我的数据,而无需遍历我的数组来对其进行预处理。

问题:

1) d3 是否有任何内置功能来处理这种情况?例如,如果在 python 中键值是绝对必要的,我们可以使用zip 函数快速生成键值列表。

2) 我可以按原样使用我的数据,还是 必须 将其转换为键值对?

下面是行示例代码。

// javascript/d3 (LINE EXAMPLE)
var margin = {top: 20, right: 20, bottom: 30, left: 50},
    width = 640 - margin.left - margin.right,
    height = 480 - margin.top - margin.bottom;

var parseDate = d3.time.format("%d-%b-%y").parse;

var x = d3.time.scale()
    .range([0, width]);

var y = d3.scale.linear()
    .range([height, 0]);

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom");

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");

var line = d3.svg.line()
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.close); });

var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

d3.tsv("/data.tsv", function(error, data) {
  data.forEach(function(d) {

    d.date = parseDate(d.date);
    d.close = +d.close;
  });

  x.domain(d3.extent(data, function(d) { return d.date; }));
  y.domain(d3.extent(data, function(d) { return d.close; }));

  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);

  svg.append("g")
      .attr("class", "y axis")
      .call(yAxis)
    .append("text")
      .attr("transform", "rotate(-90)")
      .attr("y", 6)
      .attr("dy", ".71em")
      .style("text-anchor", "end")
      .text("Price ($)");

  svg.append("path")
      .datum(data)
      .attr("class", "line")
      .attr("d", line);
});

【问题讨论】:

  • 看看 underscore.js 库中的 Object 和 zip 方法。这应该可以解决问题:http://underscorejs.org
  • 您的原始(不是屏幕截图 :) tsv 数据的样本会有所帮助。
  • @Shahram,我试图不再使用任何库,这只是另一个需要跟踪的依赖项。我希望 d3.js 已经为这种情况构建了一些东西?此外,我总是可以手动插入一个 javascript 迭代器来创建一个新对象。再一次,问题归结为:我可以用手头的图书馆来做这件事吗?即,jQuery,d3.js...
  • @patrickberkeley,我对正文进行了编辑。有一个指向原始数据集和示例的链接。

标签: javascript python arrays json d3.js


【解决方案1】:

查看d3's array functionszip 也在其中。

这是处理您的数据的原始要点的注释版本:http://bl.ocks.org/patrickberkeley/9162034

它的核心是这样的:

// 1) Zip the close value with their corresponding date/time
//    Results in an array of arrays: 
//
//    [[582.13, "02:30:00"], [583.98, "02:45:00"], ...]
//
data = d3.zip(data.close, data.date).map(function(d) {
  // 2) Format each close and date/time value so d3 understands what each represents.
  close = +d[0];

  // If your data source can't be changed at all, I'd rename `date` to `time` here.
  date = parseTime(d[1]);

  // 3) Return an object for each close and date/time pair.
  return {close: close, date: date};
});

【讨论】:

  • 太棒了!感谢您提供代码示例和 cmets。很有帮助。我认为您应该在此处的答案中包含那段代码,以帮助遇到此问题的其他任何人。我会将其标记为已接受的解决方案,因为我相信使用本机 d3 库来执行 json 请求可能是更好的设计。您的回答与下面的 Lars Kotthoff 相关。不同之处在于他的解决方案将允许我按原样使用我的数组(这需要单独的 ajax 调用)。
【解决方案2】:

您可以将其中一个数组传递给.data(),并使用索引从另一个数组中获取相应的元素:

var line = d3.svg.line()
  .x(function(d) { return x(d); })
  .y(function(d, i) { return y(tl.close[i]); });

svg.selectAll("path")
   .data([tl.date])
   .enter().append("path")
   .attr("d", line);

您只需要记住使用正确的数组设置您正在使用的比例的域。

【讨论】:

  • Lars 谢谢你的回答。您的解决方案允许我按原样使用我的数组,这是一个很好的解决方案。但我必须在两个都是有效解决方案的答案之间做出选择。我希望我能接受两者。相反,我给你一票并表示感谢。
猜你喜欢
  • 2019-03-02
  • 2021-10-25
  • 2017-06-24
  • 1970-01-01
  • 2016-10-06
  • 2014-08-30
  • 1970-01-01
  • 2012-11-19
  • 1970-01-01
相关资源
最近更新 更多