将数组中的任意值映射到另一个数组中存在的颜色

Posted

技术标签:

【中文标题】将数组中的任意值映射到另一个数组中存在的颜色【英文标题】:Map an arbitrary value from an array to a color that exists in another array 【发布时间】:2020-12-04 16:16:44 【问题描述】:

我想将任意值映射到色阶,以用于热图。

我已经能够将两种极端颜色之间的色谱生成为一个数组,如下所示:

create_color_spectrum("#b33939", "#ff5252", 20)

...给出如下输出:

["#fb5050", "#f74f4f", "#f34e4e", "#ef4d4d", "#ec4b4b", "#e84a4a", "#e44949", "#e04848", "#dc4646", "#d94545", "#d54444", "#d14343", "#cd4141", "#c94040", "#c63f3f", "#c23e3e", "#be3c3c", "#ba3b3b", "#b63a3a", "#b23838"]

现在说我有另一个像这样的值数组(values 数组)(与 colors 数组的长度相同):

[0.020565500406834823, 0.0006918573709419904, 0.03614457831325302, 0.014884840151254727, 0.9638554216867471, 0.005208333333333333, 0.0006248326341158618, 0.14285714285714285, 0.004872900466547537, 0.8571428571428577, 0, 0.2142857142857144, 0, 0.2499999999999991, 0.5000000004656613, 0.45534591194968543, 0.6349489795918367, 0.25, 0.15218156916454706, 0]

如何从 colors 数组 中为 values 数组 中的每个值提取适当的颜色?这个想法是较小的值靠近 colors 数组的开头,而较大的值靠近 colors 数组的结尾。

我需要从 values 数组 中读取一个值并将其映射到 colors 数组 中的索引。

我可以尝试重新调整 values 数组,但这不会产生不同的整数值,这是索引 colors 数组所需要的。

【问题讨论】:

【参考方案1】:

在这里,我构建了一个小对象数组,以包含值数组中的值和原始索引。然后我按值对新数组进行排序,按新索引为每个元素分配颜色,并按原始索引重新排序。

const colors = ["#fb5050", "#f74f4f", "#f34e4e", "#ef4d4d", "#ec4b4b", "#e84a4a", "#e44949", "#e04848", "#dc4646", "#d94545", "#d54444", "#d14343", "#cd4141", "#c94040", "#c63f3f", "#c23e3e", "#be3c3c", "#ba3b3b", "#b63a3a", "#b23838"];

const values = [0.020565500406834823, 0.0006918573709419904, 0.03614457831325302, 0.014884840151254727, 0.9638554216867471, 0.005208333333333333, 0.0006248326341158618, 0.14285714285714285, 0.004872900466547537, 0.8571428571428577, 0, 0.2142857142857144, 0, 0.2499999999999991, 0.5000000004656613, 0.45534591194968543, 0.6349489795918367, 0.25, 0.15218156916454706, 0];

// keep track of the old index and sort by value
const valueMap = values.map((val, i) => (oldIndex: i, value: val)).sort((a,b) => a.value - b.value);

// add the appropriate color to each element of the sorted array
valueMap.forEach((val, i) => val.color = colors[i]);
//check this console.log to verify it sorted/assigned properly
//console.log(JSON.stringify(valueMap));

// resort it by oldIndex
valueMap.sort((a,b) => a.oldIndex - b.oldIndex);

// get just the array of colors
const newColors = valueMap.map(val => val.color);
console.log(newColors);

【讨论】:

颜色似乎没有从最小值缩放到最大值:codepen.io/cybertime/pen/xxEZPOO?editors=0010 颜色根本不缩放。我只是对值进行排序,并根据新索引从颜色数组中分配一种颜色,这样较小的值朝向颜色数组的开头,而较大的值朝向结尾。这就是你想要的,对吧? 但是您的 codepen 中的代码完全符合我的预期,您遇到什么问题? 没关系,这是正确的,我很抱歉。伟大的工作。【参考方案2】:

您需要将每个值映射到颜色图中的索引。为此,您需要知道您希望看到的最小值(在您的示例中看起来像 0)、您希望看到的最大值(我猜是 1)和可用的颜色数量( 20 这里)。

// You can hard code these if you know them and want a constant representation
// The lowest possible value
const valueFloor = Math.min(...values);
// The range between the lowest and highest possible value
const valueRange = Math.max(...values) - valueFloor;

const maxColorIdx = colors.length - 1;

for (const value of values) 
    // Normalize your value to something between 0 and 1
    const normalizedValue = (value - valueFloor) / valueRange;
    // Scale your normalized value to an integerrepresenting a color index 
    const colorIdx = Math.round(normalizedValue * maxColorIdx);
    console.debug(colors[colorIdx]);

这将为您的每个值打印出“热图”颜色。

【讨论】:

似乎产生空色:codepen.io/cybertime/pen/MWjKRYy?editors=0010 @Cyber​​netic 你错过了Math.minMath.max 调用中的... 传播运算符。 啊,我的错。 ES6。谢谢。

以上是关于将数组中的任意值映射到另一个数组中存在的颜色的主要内容,如果未能解决你的问题,请参考以下文章

将一个数组的唯一值映射到另一个数组的对应总和

如何一次循环遍历 2 个数组并将数组中的颜色分配给另一个数组的每个值

VUE小练习(按钮颜色,数组映射)

输入类型='颜色'字段保存为数据库中的数组但不填充输入类型='颜色''值属性'

将数组项映射/链接到另一个对象的键

传递颜色作为道具