带间隙的路径转换 - 怎么做? [英] Path transition with gap - how do to that?

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

问题描述

我画了一些有一些缺口"的折线图(路径).我在间隙之间使用了一个技巧,然后插值不会出现在我的数据间隙之间.

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.

示例:

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

如您所见,我在位置 3 和 8 之间有一个间隙.这里我要做的是创建一个值为 0 的位置 4,以及一个值为 0 的位置 7.然后,每当我绘制折线图时,我都会得到与我的差距的正确图表.

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.

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

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 ?

我不想为我不需要表示的位置添加 0 个值,否则我的数据库会增加很多并且我的可视化会很慢.

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
}

如果您的仓位是从 0 或 1 开始计数的整数,那么此代码可以大大简化,只需使用数组的索引作为您的仓位值.如果您的位置是时间戳或其他东西,则代码会变得更加复杂.

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.

无论哪种方式,当您更新数据时,请务必检查范围是否已更改,因此是否需要填充 dataWithGaps 数组的开头或结尾(使用 pushunshift) 具有更多位置值.然后重复最后两个循环.

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.

以下示例均以包含 NaN(非数字)值作为间隙的数字数组开头,其中数组的索引用作 x 坐标.

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.

第一个例子,也许你已经这样做了,是使用 d3 路径生成器函数的 .defined(function(d){}) 方法.这允许您指出哪些数据点应该是未定义的,d3 会自动将您的线分成围绕未定义点的线段.

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

请注意,数据点是使用 SVG 线标记以便您可以看到点,即使它们没有连接到任何东西,因为它们的邻居是未定义的.

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.

(坦白时间:我是在之后发现这个的,我花了几个小时想出一个自定义的解决方案.幸运的是,我的额外时间没有浪费,因为我的d3 默认方法...)

(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...)

问题在于添加过渡时.

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

D3 不知道从哪里开始过渡的新线段.如果您只在两个现有点之间添加一个新点,它会从前一个点平滑过渡.但是,如果您有多个点添加到间隙中,它会在数组中最后一个元素的位置开始它们 - 当您添加到行尾时这可能会很好用,但看起来如果你要填补空白,那就太丑了.

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.

过渡可能可以通过自定义tween 函数,但是从头开始编写它并不容易.(不过,如果有人确实想创建一个,可能值得将其作为一个拉取请求添加到 d3 标准库中.)

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.)

与此同时,看看我创建的这种替代方法(在我仔细阅读 d3 API 以发现它们已经解决了差距之前).

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).

呸! AlaKaZAM!!! http://fiddle.jshell.net/pwmA3/3/

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

它看起来与上一个版本非常相似,除了平滑过渡,但实际上在构造上有很大不同.它不是使用单个路径来表示整条线,而是使用一系列 svg:line 元素,每个元素绘制从前一个点(如果存在)到数据点的路径.

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).

如果一个数据点不存在,它的绘图位置被插值,并且它的类被设置为触发 CSS 使线条消失,然后在给定有效数据时平滑过渡.线标记再次显示所有有效数据点,即使没有任何可链接的数据点.这是我为没有数据的点添加了问号"线标记的版本,显示了它们的位置是如何插值的:
http://fiddle.jshell.net/pwmA3/4/

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/

需要注意的一点:为每个数据点使用线段而不是路径意味着浏览器需要跟踪更多的 DOM 对象.如果您有数百个数据点,这可能会减慢速度,所有用于插入缺失点的额外计算也可能会减慢速度.如果这成为一个问题,我建议使用带有 defined() 选项的 d3 折线图方法(如第一个示例中所示),然后跳过转换.

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天全站免登陆