添加和减少重复值

  • 本文关键字:添加 javascript jitter
  • 更新时间 :
  • 英文 :


我有一个散点图(使用apexchart),我正在尝试在将数据(数组中的对象)添加到图表之前准备数据。

我的问题是,我经常有一些数据在 x 轴和 y 轴上具有完全相同的值。这意味着它们将相互重叠,并且只会显示一个项目。

我首先使用 Math.random() 为每个重复的值添加了一个简单的解决方案,但这意味着每次更新图表时它们都会稍微重新定位,这会让用户感到困惑。

因此,我想要实现的是始终为每个项目添加相同的"抖动"/更改。所以我的想法是这样做:

//1. The first three duplicates should add 0.05 to the x value. So it will say:

item1.x = 10 //original value
item2.x = 10.05
item3.x = 10.1
item4.x = 10.15

//2. Then, If more duplicates than 3, the next 3 should reduce 0.05 of the original value:
item5.x = 9.95
item6.x = 9.90
item7.x = 9.85
//If more than 7 items with the same value, then just use the original value.

如何成为实现这一目标的最佳方法?现在我有重复的值,我可以添加"抖动",但是我怎样才能让它保持计数并按照上面想要的方式做?

我设法过滤掉了重复项,但后来我卡住了:

const duplicates = AllItems.filter((val, i, self) => self.findIndex(item => item.x == val.x && item.y == val.y) != i);

有什么想法吗?

考虑使用内置Map。在这种情况下,它的性能更好,因为键值对的频繁添加和删除。

也就是说,值得一提的是,它的作用类似于哈希表实现。这个想法是通过每次发现一个出现时在其count中添加一个来跟踪给定x发生的次数。对于代码段中的points示例,请考虑以下映射表:

╔═══════╦═══════════════════════════════╗
║   x   ║ 1  2  3  4  5  6  7  8  9  10 ║
╠═══════╬═══════════════════════════════╣
║ count ║ 5  1  1  1  7  1  1  1  1  10 ║
╚═══════╩═══════════════════════════════╝

请注意,x1的点的y值不会更改,因为其计数为 5。而510会,因为它们的计数大于或等于MIN_TIMES(7)。逻辑如下:

  1. 构建地图以存储给定x点重复其y坐标的次数。
  2. 仅将每个x存储在数组中大于或等于MIN_TIMES的那些
  3. 同时,将计数更改为 0 以开始计数
  4. 映射points数组中的每个点,并根据您的逻辑将xRepeatedAtLeastMinTimes中的点转换为递增或递减。

const points=[{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:1,y:1},{x:2,y:2},{x:3,y:3},{x:4,y:4},{x:5,y:5},{x:5,y:5},{x:5,y:5},{x:5,y:5},{x:5,y:5},{x:5,y:5},{x:5,y:5},{x:6,y:6},{x:7,y:7},{x:8,y:8},{x:9,y:9},{x:10,y:10},{x:10,y:10},{x:10,y:10},{x:10,y:10},{x:10,y:10},{x:10,y:10},{x:10,y:10},{x:10,y:10},{x:10,y:10},{x:10,y:10}];
const m = new Map(),
xRepeatedAtLeastMinTimes = new Array(),
INTERVAL = 0.05,
MIN_TIMES = 7
// Construct map
points.forEach(point => m.set(point.x, m.has(point.x) ? (m.get(point.x) + 1) : 1))
// Get x coordinates that happens at least MIN_TIMES and change its count to 0
for (let [x, count] of m.entries()) 
count >= MIN_TIMES && xRepeatedAtLeastMinTimes.push(x), m.set(x, 0)
// Map each point and check condition based on count stored on Map
let result = points.map(point => {
let x = point.x
if (xRepeatedAtLeastMinTimes.includes(x)) {
let count = m.get(x)
m.set(x, count + 1)
return count === 0 ? point :
count <= 3 ? { ...point, x: x + count*INTERVAL } : 
count <= 6 ? { ...point, x: x - (count - 3)*INTERVAL } : point
}
return point
})
console.log(result)

假设有这个输入向量:

coordinates = [{x:1,y:2},{x:1,y:2},{x:10,y:1},{x:1,y:2},{x:10,y:1}]

而这个增量向量:

deltas = [0.05,0.1,0.15,-0.05,-0.1,-0.15]

此代码检索重复项,然后将增量添加到其中(如果重复项超过 6 个,则添加 0):

coordinates.map(
(e,i,v) => {
ret = !e.d
? v.reduce(
(acc,d,j) => {
if (!d.d && j != i && d.x === e.x && d.y === e.y) {
d.d=1
acc.push(d)
} 
return acc
},
[]
)
: []
e.d =1
return ret
}
)
.filter(e => e.length)
.forEach(e => e.forEach((c,i) => c.x += deltas[i] || 0))

添加用于跟踪重复项的"d"属性应被删除:

coordinates.forEach(e => delete e.d)

结果是:

coordinates
(5) [{…}, {…}, {…}, {…}, {…}]
0: {x: 1, y: 2}
1: {x: 1.05, y: 2}
2: {x: 10, y: 1}
3: {x: 1.1, y: 2}
4: {x: 10.05, y: 1}
length: 5

我认为值得将处理抖动的代码与使用该抖动更新点的代码分开。 这将使您能够尝试不同的抖动函数(阿基米德螺旋会很好),但仍然保持主逻辑不变。 下面是执行此操作的一个版本:

const updatePoints = (jitterAlgo) => (points) => 
points .reduce (({res, dups}, {x, y}) => {
const key = `${x}:${y}`
const matches = dups [key] || (dups [key] = [])
const val = jitterAlgo (matches .length, {x, y})
matches .push (val)
res .push (val)
return {res, dups}
}, {res: [], dups: {}}) .res
const customJitter = (len, {x, y, ...rest}) =>
len == 0 || len > 6
? {x, y, ... rest}
: len < 3
? {x: x + len * .05, y, ... rest}
: {x: x - len * .05, y, ... rest}
const points = [{"x": 1, "y": 6}, {"x": 3, "y": 5}, {"x": 3, "y": 5}, {"x": 5, "y": 4}, {"x": 3, "y": 5}, {"x": 3, "y": 5}, {"x": 3, "y": 5}, {"x": 1, "y": 9}, {"x": 5, "y": 4}, {"x": 5, "y": 4}, {"x": 3, "y": 5}, {"x": 2, "y": 9}, {"x": 3, "y": 5}, {"x": 3, "y": 5}, {"x": 5, "y": 4}, {"x": 2, "y": 8}]
console .log (updatePoints (customJitter) (points))
.as-console-wrapper {max-height: 100% !important; top: 0}

我确实认为,您目前的逻辑,仅在x方向上抖动,可能不会像既xy的逻辑那样令人愉快。

相关内容

  • 没有找到相关文章

最新更新