javascript - 强制 d3 折线图忽略空值

标签 javascript d3.js charts

我有一个包含空值的时间序列折线图,因此在我的线条中留下了空白。我想要做的是选择性地让 d3 线生成器忽略空值并跨越间隙。

As you can see in the image, the blue series has gaps.

如图所示,蓝色系列有间隙。

我的部分问题是我已经对这种数据格式进行了标准化:

[
  {"x":1397102460000,"y0":11.4403,"y1":96.5},
  {"x":1397139660000,"y0":13.1913,"y1":96.5},
  {"x":1397522940000,"y1":96.5},
  ...
]

因此,当一个系列具有特定时间戳的读数时,另一个系列具有空值。

最终,我可以尝试通过在绘制之前过滤我的数据来解决这个问题,但我希望有一个更聪明的解决方案,也许是关于线生成器的。

我的线生成器非常简单:

line = d3.line()
         .x(function(d) {
           return ~~_this.x(d[xKey]);
         })
         .y(function(d) {
           return ~~_this.y(d[yKey]);
         })
         .defined(function(d) {
           return d[yKey] || d[yKey] === 0;
         });

如果我删除我的 defined 方法,线条会连接起来,但 null y 值会被解释为 0px 而不是不存在。

enter image description here

有没有办法告诉线生成器不要在空数据处包含一个点?

我还应该注意,我使用的是 d3 v4.x。

最佳答案

假设您希望这条线从最后一个有效点到下一个有效点,作为一条直线,最好的想法是按照评论中的建议过滤您的数据。

line.defined 在行中创建间隙,这是预期的行为,也是此函数的用途。

因此,如果您不想过滤数据并且不想创建间隙(使用defined),您可以更改线生成器函数。这不是一个好主意,它是一段丑陋的代码,但它是可行的。

设置一个计数器:

var counter;

如果值有效 (!= null),增加计数器。如果不是,则告诉行生成器保留最后一个有效值:

var line = d3.line()
    .x((d, i) => {
        if (data[i].y) {
            return xScale(d.x)
        } else {
            return xScale(data[counter].x)
        }
    })
    .y((d, i) => {
        if (d.y) {
            counter = i;
            return yScale(d.y)
        } else {
            return yScale(data[counter].y)
        }
    });

在此演示中,该行从第五个数据点(最后一个有效值)跳到第九个数据点(下一个有效值):

var w = 500,
    h = 300;
var svg = d3.select("body")
    .append("svg")
    .attr("width", w)
    .attr("height", h);

var data = [{
    x: 10,
    y: 50
}, {
    x: 20,
    y: 70
}, {
    x: 30,
    y: 20
}, {
    x: 40,
    y: 60
}, {
    x: 50,
    y: 40
}, {
    x: 60,
    y: null
}, {
    x: 70,
    y: null
}, {
    x: 80,
    y: null
}, {
    x: 90,
    y: 90
}, {
    x: 100,
    y: 20
}];

var xScale = d3.scaleLinear()
    .domain([0, 100])
    .range([30, w - 20]);

var yScale = d3.scaleLinear()
    .domain([0, 100])
    .range([h - 20, 20]);

var counter;

var line = d3.line()
    .x((d, i) => {
        if (data[i].y) {
            return xScale(d.x)
        } else {
            return xScale(data[counter].x)
        }
    })
    .y((d, i) => {
        if (d.y) {
            counter = i;
            return yScale(d.y)
        } else {
            return yScale(data[counter].y)
        }
    });

svg.append("path")
    .attr("d", line(data))
    .attr("stroke-width", 2)
    .attr("stroke", "teal")
    .attr("fill", "none");

var xAxis = d3.axisBottom(xScale);
var yAxis = d3.axisLeft(yScale);

svg.append("g")
    .attr("transform", "translate(0," + (h - 20) + ")")
    .call(xAxis);

svg.append("g")
    .attr("transform", "translate(30,0)")
    .call(yAxis);
<script src="https://d3js.org/d3.v4.min.js"></script>

关于javascript - 强制 d3 折线图忽略空值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40873931/

相关文章:

javascript - redux 和状态机(例如 xstate)之间的实际区别是什么?

javascript - 多个 jQuery actions() 一次发生?

javascript - HTML5 Canvas : Change Image Color

javascript - 如何使在按钮上实现的加载旋转器在脚本运行完成后停止?

d3.js - 在两个重叠元素上捕获鼠标悬停事件

haskell - Yesod 的图表解决方案

javascript - 从 Canvas 中删除/取消绑定(bind) d3 缩放

javascript - 使用 NodeSize 节点之间的 D3 树布局分离

javascript - Recharts - 归一化堆叠条形图

java - 使用 Python 或 Java,创建图表的最佳方式是什么?