【问题标题】:Append Circles to 1 Line in a D3 Multi-Line chart将圆圈附加到 D3 多线图中的 1 条线上
【发布时间】:2014-01-24 04:54:56
【问题描述】:

我有一个多折线图,表示给定日期的 8 个不同系列的值: http://bl.ocks.org/eoiny/8548406

我已经设法过滤掉 series1 并仅为 series1 的每个数据点附加圆圈,使用:

var filtered = city
      .filter(function(d){
          return d.name == "series1"
      })

      filtered           
            .selectAll('circle')
            .data(
              function(d){return d.values}                
                  )
            .enter().append('circle')
            .attr({
              cx: function(d,i){
                return x(d.date)
              },
              cy: function(d,i){
                return y(d.pindex)
              },
              r:  5
            })

但是我试图在我的 series1 行中添加 4 个圆圈,每个圆圈仅用于以下值:

  1. series1 中的最小值,
  2. 系列1中的最大值,
  3. 系列1中的第一个值,
  4. series1 中的最后一个值。

我通过查看“过滤”数组来解决这个问题,并尝试使用类似这样的方法来捕获最小值和最大值:

.attr("visibility", function(d) {
     if (d.pindex == d3.max(filtered, function(d) { return d.pindex; })) {return "visible"}
     if (d.pindex == d3.min(filtered, function(d) { return d.pindex; })) {return "visible"}
     else    { return "hidden" }  
                 ;}) 

但我不知何故被我需要的数据位于过滤数组中的对象中这一事实弄糊涂了。我知道过滤后的应该是这样的:

[{
name: "series1",
  values: [{date: "2005-01-01",
               pindex: "100"},
              {date: "2005-02-01"
              pindex: "100.4"}, ...etc for all data points i.e. dates
             ]
    }] 

所以我尝试了这样的事情:

d.pindex == d3.max(filtered, function(d) { return d.values.pindex; })

但我还是有点迷茫。有人有什么想法吗?

【问题讨论】:

  • 创建一个最小的小提琴总是有帮助的。 d3.max 中的函数应该是function(d,i) {return d.values[i].pindex;},因为 values 是一个数组吗?
  • 您也可以使用原始数据本身 (cities) 而不是 D3 包装的对象。
  • @FernOfTheAndes 我尝试使用:'.attr("visibility", function(d) { if (d.pindex == d3.max(filtered, function(d,i) {return d. values[i].pindex;})) {return "visible"} else { return "hidden" } ;}) '
  • 我收到此消息:未捕获类型错误:无法读取未定义的属性“0”
  • 有点切线,但我建议,不要为这些特殊值创建一组全新的圆元素,您只需根据数据更改初始圆本身的类/样式。跨度>

标签: d3.js


【解决方案1】:

一般来说,您可能想要过滤您的 数据 而不是 DOM 元素。因此,您可以使用cities.filter 来获取您感兴趣的数据数组,而不是使用city.filter。更重要的是,您可能希望过滤传递给新circle 选择的数据,而不是创建所有圆圈然后选择性地显示或隐藏它们。我可以试试:

filtered           
    .selectAll('circle')
    .data(function(d){
        var points = d.values;
        // create the array of desired points, starting with the easy ones
        var circleData = [
            // first
            points[0],
            // last
            points[points.length - 1]
        ];
        // now find min and max
        function getValue(d) { return d.pindex; }
        // d3.max returns the max value, *not* the object that contains it
        var maxVal = d3.max(points, getValue);
        // Note that you might have multiple points with the max. If you
        // don't want them all, just take maxPoints[0]
        var maxPoints = points.filter(function(d) { return d.pindex === maxVal; });
        // same for min
        var minVal = d3.min(points, getValue);
        var minPoints = points.filter(function(d) { return d.pindex === minVal; });
        // stick them all together
        return circleData.concat(maxPoints).concat(minPoints);
    })
    .enter().append('circle')
    // etc

关键点:

  • 过滤您的数据,而不是您的 DOM。它的处理成本更低,更容易调试,而且通常更容易理解。

  • d3.mind3.max 不返回具有最大值的对象,它们返回值本身,因此您的 TypeError

【讨论】:

  • 感谢一百万!它可以工作(对查找 maxPoints 和 minPoints 的功能进行小幅编辑)!我明白你所说的关于过滤数据而不是 DOM 的内容。感谢您的提醒,它清除了很多东西。
猜你喜欢
  • 2020-01-21
  • 1970-01-01
  • 1970-01-01
  • 2014-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-16
  • 1970-01-01
相关资源
最近更新 更多