D3.js 我在哪里可以找到一个好的折线图标签放置算法?

D3.js 我在哪里可以找到一个好的折线图标签放置算法?,d3.js,data-visualization,visualization,linechart,D3.js,Data Visualization,Visualization,Linechart,我希望在折线图上自动将系列标签放在其线条附近,如下面《经济学人》中的示例所示。我使用的是D3,但我很乐意使用其他语言的优秀解决方案,我可以将其翻译成JavaScript或从中获得灵感 我发现了一些将标签放置在线条右侧的方法,例如使用强制定向布局。我也尝试过做类似的事情。这通常效果很好,但当多个序列的最右侧点靠近时会导致问题。我觉得我们可以用“如果一个系列有几个连续的值,这些值高于绘图上的所有其他系列,则将标签置于这些值之上”这样的规则走得更远,比如上图中的英国或美国 我真的很感激任何指向实现这

我希望在折线图上自动将系列标签放在其线条附近,如下面《经济学人》中的示例所示。我使用的是D3,但我很乐意使用其他语言的优秀解决方案,我可以将其翻译成JavaScript或从中获得灵感

我发现了一些将标签放置在线条右侧的方法,例如使用强制定向布局。我也尝试过做类似的事情。这通常效果很好,但当多个序列的最右侧点靠近时会导致问题。我觉得我们可以用“如果一个系列有几个连续的值,这些值高于绘图上的所有其他系列,则将标签置于这些值之上”这样的规则走得更远,比如上图中的英国或美国


我真的很感激任何指向实现这种功能的指针

下面是一个简单的D3代码片段,它试图模仿经济学人的例子,在一个系列中寻找在该点上所有系列都是异常值的点。此外,通过检查最高离群值是否比最低离群值更离群,可以确定标签的最佳点

例如,对于折线图,你将有一组系列

[
  {
    "id": "A",
    "values": [{"index": 1, "value": 10}, ... {"index": n, "value": 35}]
  },
  {
    "id": "B",
    "values": [{"index": 1, "value": 20}, ... {"index": n, "value": 200}]
  },
  ... etc
]
因此,您可以计算每个索引的IQR的高点和低点(使用
d3.分位数(arr,x)
,其中
x
0.25
0.75

  const iqrLows = d3.range(valueCount).map((n, i) => {
    const values = sampleLabels.map((label, i2) => series[i2].values[i]).map(o => o.value);
    return d3.quantile(values, 0.25);
  });
  const iqrHighs = d3.range(valueCount).map((n, i) => {
    const values = sampleLabels.map((label, i2) => series[i2].values[i]).map(o => o.value);
    return d3.quantile(values, 0.75);
  });
然后,对于每个系列,寻找低于低点或高于高点的点。然后,如果最高离群值大于最低离群值,则可以将标签放在该点上方。或者,如果最低离群值大于最高离群值,则将标签放在该点下方

  series.forEach(s => {
    const compareLows = s.values.map((k, i) => k.value < iqrLows[i] ? iqrLows[i] - k.value : 0);
    const compareHighs = s.values.map((k, i) => k.value > iqrHighs[i] ? k.value - iqrHighs[i] : 0);
    if (d3.max(compareHighs) > d3.max(compareLows)) {
      s.xLabelIndex = d3.maxIndex(compareHighs) + 1;
      s.xLabelValue = s.values[d3.maxIndex(compareHighs)];
      s.xLabelOrient = "above";
    } else {
      s.xLabelIndex = d3.maxIndex(compareLows) + 1; 
      s.xLabelValue = s.values[d3.maxIndex(compareLows)];
      s.xLabelOrient = "below";
    }
  });

生成

我建议使用标注:ggrepel是一个r库,在使用ggplot时帮助放置标签:-可能会提供一些想法。