D3js - 从 d3.line() 获取特定域的最大值

mar*_*n36 5 javascript d3.js

我正在制作一个多折线图,并且我已经实现了一个画笔,以便能够放大 x 轴上的特定域。但是,当我放大时,我希望 y 轴缩放,以便它的域从 开始[0, maxY],其中maxY是 x 轴上当前选择的最大 y 值。生成我正在使用的线条d3.line()(它具有 x 和 y 值之间的连接)。这是我目前计算maxY值的方式:

//Find max and min values in data to set the domain of the y-axis
var maxArray = updatedData.map(function(variable){
  //First map the values in the array to a new array
  var valuesArray = variable.values.map(function(d){
    return d.value;
  })
  //Find max value in array
  return Math.max(...valuesArray);
});
var maxY = Math.max(...maxArray);
Run Code Online (Sandbox Code Playgroud)

这是我设置比例并创建的地方d3.line()

var xScale = d3.scaleTime()
  .range([0, chartWidth]);
var yScale = d3.scaleLinear()
  .domain([0, maxY])
  .range([chartHeight, 0]);

var brush = d3.brushX()
  .on("end", brushend);

var line = d3.line()
  .curve(d3.curveBasis)
  .x(function(d) {return xScale(d.date)})
  .y(function(d) {return yScale(d.value)})

//Save this to be able to zoom back out
var originalDomain = [new Date(data[0].Timestamp), new Date(data[data.length-1].Timestamp)];
xScale.domain(originalDomain);
Run Code Online (Sandbox Code Playgroud)

这是我设置新的xScale.domain()并在该间隔上放大的代码(在刷牙结束时调用):

function brushend(){
  //sourceEvent - the underlying input event, such as mousemove or touchmove.
  if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return; // ignore zoom-by-brush
  var brushInterval = d3.event.selection; //The interval of the current brushed selection
  //If the function is called with no selection: ignore
  if(!brushInterval) return;
  //Enable reset button
  resetButton.attr("disabled", null)
    .on("click", resetAxis);

  var newDomain = brushInterval.map(xScale.invert, xScale);

  //TODO: Find max and min values in data to set the domain of the y-axis

  xScale.domain(newDomain);
  chart.selectAll(".line")
    .transition()
    .duration(1000)
      .attr("d", function(d){ return line(d.values)});
  chart.select(".x-axis")
    .transition()
    .duration(1000)
      .call(xAxis);
  //Remove the visual brush
  d3.select(".brush").call(brush.move, null);
}
Run Code Online (Sandbox Code Playgroud)

我想做的是在当前选定的域中找到最大的 y 值。我知道我可以过滤数据值以删除不在当前选定域中的数据值,然后从中计算最大值(就像我对原始域所做的那样)。但似乎应该有一个更简单的解决方案。我没有在文档中找到任何d3.line()可以计算最大值的函数。

有什么简单的方法可以计算最大值d3.line()吗?

谢谢

alt*_*lus 3

实际上没有更简单的解决方案,因为您必须以某种方式过滤这些值以仅考虑您选择的 x 域中的值。然而,使用两个嵌套调用d3.max()至少可以给它一个令人愉快的外观,并通过避免对 的额外调用来节省一些迭代.filter()。由于d3.max()将忽略null值,因此您可以使用它来过滤您的值,方法是返回null当前数据是否超出 x 域的边界。要获得最大值,您可以使用如下所示的内容:

const maxY = xDomain => d3.max(updatedData, variable => 
  d3.max(
    variable.values,
    v => v.Timestamp >= xDomain[0] && v.Timestamp <= xDomain[1] ? v.value : null
  )
);
Run Code Online (Sandbox Code Playgroud)

看看下面的代码片段,了解一个有效的演示:

const maxY = xDomain => d3.max(updatedData, variable => 
  d3.max(
    variable.values,
    v => v.Timestamp >= xDomain[0] && v.Timestamp <= xDomain[1] ? v.value : null
  )
);
Run Code Online (Sandbox Code Playgroud)
var updatedData = [{
  values: [{Timestamp:0, value:1},{Timestamp:1, value:5},{Timestamp:2, value:10},{Timestamp:3, value:3},{Timestamp:4, value:30}]
}, {
  values: [{Timestamp:0, value:19},{Timestamp:1, value:12},{Timestamp:2, value:13},{Timestamp:3, value:8},{Timestamp:4, value:50}]
}];

const maxY = xDomain => d3.max(updatedData, variable => 
  d3.max(
    variable.values,
    v => (!xDomain || v.Timestamp >= xDomain[0] && v.Timestamp <= xDomain[1]) ? v.value : null
  )
);

console.log(maxY());       // Default, check all values: max 50
console.log(maxY([1,3]));  // Max 13
console.log(maxY([0,3]));  // Max 19
Run Code Online (Sandbox Code Playgroud)