algorithm - 自动选择图例的比例(线性、幂、对数)

标签 algorithm math d3.js graph data-science

与 d3.js 相比,这更像是一个数据科学问题,但我想其他人也一定也考虑过这一点。

我有一个包含每日更新值的数据集。该集合还包含所有或几天的历史数据。基本上是这样的:

{data: [
    "ItemA" : {
        "24.10.2020" : 123,
        "25.10.2020" : 134,
        "26.10.2020" : 145,
        "27.10.2020" : 156,
        "28.10.2020" : 167      
    },
    "ItemB" : {
        "24.10.2020" : 123,
        "25.10.2020" : 234,
        "26.10.2020" : 456,
        "27.10.2020" : 567,
        "28.10.2020" : 678      
    },
    "ItemC" : {
        "24.10.2020" : 123,
        "25.10.2020" : 136,
        "26.10.2020" : 149,
        "27.10.2020" : 152,
        "26.10.2020" : 165,
        "28.10.2020" : 178      
    },
]}

如您所见,ItemB 是一个异常值,其值的增长速度比其他 Item 的值增长得快得多。

只要值以几乎相同的速度增长,为图例设置一个比例来显示随时间的增长就很容易。 d3.scaleLinear().domain([0, upperBoundValues]) 很好。当值增长时,用户仍然可以区分较小和较高的值。

由于一项项目增长较快,因此增长较慢的项目会被插入规模的一部分。因此,如果我有一个像 d3.interpolateTurbo 这样的颜色范围,突然大多数值都会显示为接近黑色的颜色,而一个总是显示为红色。

我会手动切换到功率标度或对数标度。特别是因为我必须每天检查发生了什么。

我希望有一个函数可以测试此类开发并自动切换值的比例。更好的是选择一个拟合标度(基本上选择功率标度和/或对数标度的基数的最佳拟合指数)。 如果我的值永远不会增长到超大数字,我就不需要以 10 为底的对数刻度。

是否有任何我可以实现的近似函数/算法可以使选择更容易,或者在我可以选择比例时返回一个值(例如:0...1 -> Linear//1...n -> Log )

最佳答案

作为我的评论的扩展,请考虑以下内容,其中使用 scaleThreshold 和十分位值。我画了5个圆圈,第一个圆圈的值(value)比其他圆圈增长得快得多。但由于阈值比例的原因,您仍然会看到它们之间存在足够的差异。

const data = d3.range(5).map(i => {
  let values = [1];
  d3.range(50).forEach(() => {
    // Either a multiplier [0.9, 1.2], or (if it's the first one, [1.2, 1.5]
    const multiplier = (i === 0 ? 1.2 : 0.9) + (Math.random() * 0.3);
    values.push(values[values.length - 1] * multiplier);
  });

  return {
    x: 50 + i * 100,
    y: 50,
    r: 40,
    values: values,
  };
});

const allValues = data.map(d => d.values).flat().sort((a, b) => a - b);
const colours = d3.scaleThreshold()
  .domain([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9].map(i => d3.quantile(allValues, i)))
  .range(d3.schemeSpectral[10]);

const svg = d3.select("svg")
  .attr("width", 500);

const colourbar = svg.append("g");

colourbar
  .selectAll("rect")
  .data(colours.range())
  .enter()
  .append("rect")
  .attr("x", (d, i) => i * 50)
  .attr("y", 100)
  .attr("height", 20)
  .attr("width", 50)
  .attr("fill", d => d);

colourbar
  .selectAll("text")
  .data(colours.domain())
  .enter()
  .append("text")
  .attr("x", (d, i) => (i + 1) * 50)
  .attr("y", 135)
  .text(d => d.toFixed(1));

const circles = svg.append("g")
  .selectAll("circle")
  .data(data)
  .enter()
  .append("circle")
  .attr("cx", d => d.x)
  .attr("cy", d => d.y)
  .attr("r", d => d.r);

const labels = svg
  .append("g")
  .selectAll("text")
  .data(data)
  .enter()
  .append("text")
  .style("fill", "white")
  .attr("dy", 5)
  .attr("x", d => d.x)
  .attr("y", d => d.y);

let counter = -1;

function colour() {
  counter = (counter + 1) % 50;
  labels.text(d => d.values[counter].toFixed(1));
  circles
    .transition()
    .duration(1000)
    .ease(d3.easeLinear)
    .attr("fill", d => colours(d.values[counter]))
    .filter((d, i) => i === 0)
    .on("end", colour);
}

colour();
text {
  text-anchor: middle;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>

关于algorithm - 自动选择图例的比例(线性、幂、对数),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64544680/

相关文章:

python-3.x - 这个函数的时间复杂度是多少,它生成一个数字的所有唯一因子组合?

sqlite - 数学表达式在Google中有效,但在sqlite或KornShell中无效。

c++ - 开源 C/C++ 数学表达式解析器库

javascript - 为什么我的 D3 SVG 图上的轴不会更新?

javascript - 文件比较脚本的逻辑

java - 获取字符串输入,将每个单词解析为全部小写并在一行上打印每个单词,非字母字符被视为单词之间的分隔符

c++ - 移动窗口 RMQ 性能改进

python - 在 YAML 中执行算术运算?

javascript - d3 停止传播 - "mousedown.log"

javascript - NVD3时间格式,带焦点图的线