与差距的路径转换 - 怎么办? [英] Path transition with gap - how do to that?

查看:105
本文介绍了与差距的路径转换 - 怎么办?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我绘制一些具有一些差距的折线图(路径)。



例如:









b $ b

  pos,value 
1,10
2,15
3,20
8,5
9,6
10,20

正如你所看到的, 3和8.这里我做的是创建一个值为0的位置4和一个值为0的位置7.然后,每当我绘制我的折线图,我得到正确的图表与我的差距。



现在,我需要在此折线图上进行转换。由于我有这个差距黑客,我的过渡是不美丽的:(
这种移动线以一种我不喜欢的方式。



我应该怎么办?
在这种情况下是否可以进行转换,而不需要在我的间隙之间有很多0值?



我't想为位置添加0值,我不需要表示,否则我的数据库将增加一个LOT,我的可视化会很慢。



任何洞察是高度赞赏。

解决方案

你需要做的第一件事你更新函数是创建一个新的数据数组填充缺少例如:

  var data = [/ *你的原始数据表* /]; 
// d3.tsv或任何你使用的结果

var posRange = d3.max(data,function(d){return d.pos;});
//将最大和最小pos值作为双元素数组获取
var dataWithGaps = new Array(posRange [1] + 1 - posRange [0]);
// ie,数组的长度是位置差,
//加1以包括最后一个位置
//(例如对于位置2-5,您需要4个元素2, 3,4,5,这是5 + 1-2

var j = dataWithGaps.length;
while(j - ){//计算新数组的长度
dataWithGaps [j] = {pos:posRange [0] + j,value:NaN};
//创建有效位置和未定义值
}
j = data.length;
while(j - ){//扫描数据并复制
d = data [j];
dataWithGaps [d.pos-posRange [0]] value = d。 value;
//在新数组中找到正确的索引,并设置它的值
}

如果你的位置是从零或一个整数计数,那么这个代码可以大大简化,只是使用数组的索引作为你的位置值如果你的位置是时间戳或别的,复杂。



无论哪种方式,当您更新数据时,请务必检查范围是否已更改,因此是否需要填充<具有更多位置值的code> dataWithGaps 数组( push unshift 。然后重复最后两个循环。



现在绘制...



包含 NaN (not-a-number)值作为空格的数组数组,其中数组的索引用作x坐标。



第一个例子,也许你已经在做这件事,就是使用d3 path-generator函数的 .defined(function(d){})



Ta-Dah! > http://fiddle.jshell.net/9jTk4/2/



魔术代码是这个链中最后一个语句:

  var drawLine = d3 .svg.line()
.x(function(d,i){return xScale(i);})
.y(function(d){return yScale(d);})
.defined(function(d){return!isNaN(d)});
//该行应该只定义在数据值不为NaN的地方
//如果你的数据值是对象,则使用!isNaN(d.value)

请注意,数据点是使用 SVG line markers ,以便您可以看到点,即使他们没有连接到任何东西,因为他们的邻居是未定义的。



我在这之后只发现了我花了几个小时提出了一个自定义解决方案。幸运的是,我的额外时间并没有浪费, d3默认方法...)



问题是添加转换时。



Dum-da- DUM(不祥的器官和弦) http://fiddle.jshell.net/9jTk4/1/



D3不能不知道在哪里开始新的线段过渡。如果你只是在两个现有点之间添加一个新点,它会从上一个点平滑过渡。然而,如果你有多个点加入到一个差距,它开始他们在数组中的最后一个元素的位置 - 这可能会很好,当你添加到行尾,但看起来



转换可能需要使用自定义 tween 函数,但这不是直接从头开始写。 (虽然,如果有人想要创建一个,它可能值得一个pull请求添加到d3标准库。)



同时,看看我创建的这种替代方法(在我仔细阅读d3 API之前,发现它们已经解决了空白)。



Ta-Dah! AlaKaZAM !!! http://fiddle.jshell。 net / pwmA3 / 3 /



它看起来非常类似于最后一个版本,除了平滑过渡,但实际上在结构上是非常不同的。它使用一系列 svg:line 元素,而不是使用单个路径表示整个行,每个元素从上一个点绘制路径到数据点(如果存在)。



如果数据点不存在,它的绘制位置是插值的,它的类设置为触发CSS,使线条消失,然后平滑过渡当它给出有效的数据。线标记再次显示所有有效的数据点,即使没有什么可以链接到。这里有一个版本,我为没有数据的点添加了问号线标记,显示了它们的位置是如何内插的:

http://fiddle.jshell.net/pwmA3/4/



有一点需要注意:使用每个数据点的线段而不是路径意味着更多的DOM对象供浏览器跟踪。如果你有数百个数据点,这可能会减慢事情,因为所有额外的计算,用于内插缺失的点。如果这成为一个问题,我建议使用d3线图方法与 defined()选项(如第一个例子),只是跳过转换。 / p>

I draw some line chart (path) that has some "gaps". I use a trick between the gaps, then the interpolation doesn't appears between the gaps I have on my data.

Example:

pos, value
1,10
2,15
3,20
8,5
9,6
10,20

As you can see, I have a gap between position 3 and 8. Here what I do is to create a position 4 with value 0, and a position 7 with value 0. Then, whenever I plot my line chart I get the correct chart with my gap.

Now, I need to make a transition on this line chart. Given I have this "gap hack", my transition is not beatiful :( It kind of move lines in a way that I don't like.

What should I do ? Is it possible to make a transition in this case without the need of having a lot of 0 values between my gaps ?

I don't want to add 0 values for positions I don't need to represent, otherwise my database will increase a LOT and my visualization would be slow.

Any insight is highly appreciated.

解决方案

The first thing you need to do in you update function is to create a new data array the fills in the missing values for your position variable, while leaving the value variable undefined. Something like:

var data = [/* Your original data table */];
       //results of d3.tsv or whatever you use

var posRange = d3.max(data, function(d){return d.pos;});  
    //get the max and min pos values as a two-element array
var dataWithGaps = new Array(posRange[1] + 1 - posRange[0] );
    //i.e., length of the array is the difference in position, 
    //plus 1 to include the last position 
    //(eg for positions 2-5 you need 4 elements 2,3,4,5, which is 5+1-2

var j=dataWithGaps.length;
while (j--){ //count down the length of the new array
    dataWithGaps[j] = {pos:posRange[0]+j, value:NaN}; 
        //create a valid position and undefined value
}
j=data.length;
while (j--){//scan through the data and copy over
    d = data[j];
    dataWithGaps[d.pos-posRange[0]].value = d.value; 
      //find the correct index in the new array, and set it's value
}

If your positions are integers counting up from zero or one, then this code can be simplified considerably, just using the index of the array as your position values. If your positions are timestamps or something else, the code gets more complicated.

Either way, when you update your data, be sure to check whether the range has changed, and therefore whether you need to pad the start or end of your dataWithGaps array (with push or unshift) with more position values. Then repeat the last two loops.

Now to graphing...

The following examples all start with an array of numbers containing NaN (not-a-number) values as gaps, where the index of the array is used as the x-coordinate.

First example, maybe you were already doing this, is to use the d3 path-generator function's .defined(function(d){}) method. This allows you to indicate which data points should be undefined, and d3 automatically breaks your line into segments around the undefined points.

Ta-Dah! http://fiddle.jshell.net/9jTk4/2/)

The magic code is the last statement in this chain:

var drawLine = d3.svg.line()
    .x(function(d,i) { return xScale(i); })
    .y(function(d) { return yScale(d); })
    .defined(function(d) {return !isNaN(d)});
    //the line should be only be defined at points where the data value is not NaN
    //use !isNaN(d.value) if your data values are objects

Note that the data-points are made using SVG line markers so that you can see points even if they don't connect to anything because their neighbours are undefined.

(Confession time: I only discovered this after I spent a few hours coming up with a custom solution. Luckily, my extra time wasn't wasted because there is a flaw with the d3 default approach...)

The problem is when you add a transition.

Dum-da-DUM (Ominous organ chords) http://fiddle.jshell.net/9jTk4/1/

D3 can't doesn't know where to start the new line segment for the transition. If you're only adding one new point in between two existing points, it transitions smoothly from the previous point. However, if if you've got multiple points adding in to a gap it starts them out at the position of the final element in the array -- which might work great when you're adding on to the end of the line, but looks pretty ugly if you're filling in gaps.

The transition could probably be fixed with a custom tween function, but that's not going to be straightforward to write from scratch. (Though, if someone does want to create one, it would probably be worth making it a pull request to be added to the d3 standard library.)

In the meantime, take a look at this alternative approach I created (before I read the d3 API carefully enough to discover that they already account for gaps).

Ta-Dah! and AlaKaZAM!!! http://fiddle.jshell.net/pwmA3/3/

It looks very similar to the last version, except with smooth transitions, but it is actually very different in construction. Instead of using a single path to represent the entire line, it uses a series of svg:line elements, each of which draws the path up to the data point from the previous point (if it existed).

If a data point doesn't exist, it's plotting position is interpolated, and it's class is set to trigger CSS that makes the line disappear, and then transitions it in smoothly when it's given valid data. Line-markers again show all the valid data points, even if there is nothing to link them to. Here's a version where I've added a "question mark" line marker for the points with no data, showing how their positions were interpolated:
http://fiddle.jshell.net/pwmA3/4/

One thing to note: using line segments for each data point instead of a path means a lot more DOM objects for the browser to keep track of. If you have many hundreds of data points, this could slow things down, as could all the extra computation for interpolating the missing points. If that becomes a problem, I'd recommend using the d3 line graph method with the defined() option (as in the first example), and just skip the transition.

这篇关于与差距的路径转换 - 怎么办?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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