【问题标题】:D3: skip null values in line graph with several linesD3:在具有多条线的折线图中跳过空值
【发布时间】:2014-09-22 19:07:42
【问题描述】:

我有一个动态数组来显示带有多条线的折线图。示例:

var data = 
[[{x:2005, y:100}, {x:2007, y:96.5}, {x:2009, y:100.3}, {x:2011, y:102.3}], 
 [{x:2005, y:100}, {x:2007, y:105},  {x:2009, y:102},   {x:2011, y:104}]]

我的脚本的这一部分将画线:

graph.selectAll("path.line")
.data(data)
.enter().append("path")
.attr("class", "line")
.style("stroke", function(d, i) { return d3.rgb(z(i)); })
.style("stroke-width", 2)
.attr("d", d3.svg.line()
.y(function(d) { return y(d.y); })
.x(function(d,i) { return x(i); }));

(我使用的脚本是基于http://cgit.drupalcode.org/d3/tree/libraries/d3.linegraph/linegraph.js

我的问题:数据数组是动态的,我事先不知道里面有什么。有时 2005 年的 y 值为空:

var data = 
[[{x:2005, y:100},  {x:2007, y:96.5}, {x:2009, y:100.3}, {x:2011, y:102.3}], 
 [{x:2005, y:null}, {x:2007, y:105},  {x:2009, y:102},   {x:2011, y:104}]]

如何让第二行忽略第一个对象,并从 2007 年开始?

根据答案 1,这就是我现在所拥有的,仍然显示整行:

data = 
[[{x:2005, y:100},  {x:2007, y:96.5}, {x:2009, y:100.3}, {x:2011, y:102.3}], 
 [{x:2005, y:null}, {x:2007, y:105},  {x:2009, y:102},   {x:2011, y:104}]];

var validatedInput = function(inptArray) { 
 return inptArray.filter(function(obj) {
  return obj.y != null;
 });
};

graph.selectAll("path.line")
    .data(data, validatedInput)
  .enter().append("path")
    .attr("class", "line")
    .style("stroke", function(d, i) { return d3.rgb(z(i)); })
    .style("stroke-width", 2)
    .attr("d", d3.svg.line()
    .y(function(d) { return y(d.y); })
    .x(function(d,i) { return x(i); }));

【问题讨论】:

    标签: javascript d3.js


    【解决方案1】:

    最后我自己解决了这个问题,基于解决方案here。诀窍是尽可能晚地删除空值,以便保留画布上所有值(点)的位置。

    graph.selectAll("path.line")
        .data(data)
      .enter().append("path")
        .attr("class", "line")
        .style("stroke", function(d, i) { return d3.rgb(z(i)); })
        .style("stroke-width", 2)
        .attr("d", d3.svg.line()
        .y(function(d) { return y(d.y); })
        .defined(function(d) { return d.y; }) // Omit empty values.
        .x(function(d,i) { return x(i); }));
    

    这适用于行首和行尾的空值。

    【讨论】:

    • 嘿@eingebruiker,您能解释一下defined() 行的工作原理并让您省略空值吗?
    • @user3768495 呃,那是一年多以前的事了,从那以后我就没有看过它:-) 我相信它是这样工作的:它充当过滤器。看最后三行。首先确定画布上所有点的 y 位置。然后,通过使用 defined(),删除 y == null 的点。然后确定剩余点的x位置。
    【解决方案2】:

    应该这样做:

    .data(data, function(inptArray) { 
      return inptArray.filter(function(obj) {
       return obj.y != null;
      }) 
    });
    

    这样写会更好:

    var validatedInput = function(inptArray) { 
     return inptArray.filter(function(obj) {
      return obj.y != null;
    });
    
    .data(data, validatedInput);
    

    或者您可以在将数据对象提供给 D3 之前对其进行格式化:

    var data = data.map(function(obj){
     return obj.filter(function(obj) {
      return obj.y != null;
     })
    })
    

    【讨论】:

    • 嗨,sergeyz,我尝试了你的建议,但现在根本没有生成第二行。
    • 你有两个对象数组还是应该是一个对象数组?还有 { x=2005, y=100} 表示 { x: 2005, y: 100} 对吧?
    • 在您的示例中,您有一个分配给数据变量的数组和另一个未分配给任何东西的数组。一个数组: var data = [{ x=2005, y=100}, { x=2007, y=96.5}, { x=2009, y=100.3}, { x=2011, y=102.3}] 另一个数组: [{ x=2005, y=null}, { x=2007, y=105}, { x=2009, y=102}, { x=2011, y=104}] 当你在 DevTool 中时,检查里面有什么将数据传递给 .data 之前的数据。
    • 哦,抱歉,我是从 Firebug 中的 console.log 复制的,有点太仓促了。 data 实际上是一个对象数组的数组。我用正确的数据数组修改了我的问题。
    • 我尝试了您的 validateInput(最后缺少一个额外的 })。现在我有两个完整的行,包括空值。所以它还没有工作。
    猜你喜欢
    • 2019-07-24
    • 2020-12-23
    • 2017-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-27
    • 1970-01-01
    相关资源
    最近更新 更多