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