这更多的是一个数据科学的问题,而不是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是一个异常值,其值的增长要比其他项的值增长得快得多。
建立一个图表的比例来显示随着时间的增长是很容易的,只要数值以几乎相同的速度增长。一个d3.scaleLinear().domain([0, upperBoundValues])很好。当值增加时,用户仍然可以区分较小的值和较高的值。
由于一个项目增长得更快,增长较慢的项目被推到了规模的一个部分。因此,如果我有一个像d3.interpolateTurbo这样的颜色范围,那么大多数值都会被显示为接近黑色的颜色,而一个总是显示到红色的颜色。
我会手动切换到电源秤或者日志秤。尤其是因为我每天都要检查会发生什么。
我更希望有一个函数来测试这样的开发,并自动切换标度,如果值。更好的是,选择一个合适的标度(基本上选择幂标度和/或对数标度的最佳拟合指数)。如果我的值永远不会增长到超大值,我就不需要base10日志刻度。
是否有任何近似函数/算法可以使选择更容易,或者返回一个值,我可以选择标度(例如:0.1 ->线性/1.n ->日志)
发布于 2020-10-26 22:06:40
作为我的注释的扩展,请考虑以下内容,它使用带有十进制值的scaleThreshold。我画了5个圆圈,第一个圆圈的增值比其他的快得多。但你仍然会看到他们之间的差异,因为阈值尺度。
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>
https://stackoverflow.com/questions/64544680
复制相似问题