xxxxxxxxxx
173
let dataPoints = []
let centroids = []
let stop = false
const euclidianDistance = (point1, point2) => {
const d1 = (point2.x - point1.x)**2
const d2 = (point2.y - point1.y)**2
return Math.sqrt(d1 + d2)
}
class DataPoint {
constructor(xPosition, yPosition, gColor){
this.x = xPosition
this.y = yPosition
this.groupColor = gColor
this.diameter = 10
}
show() {
noStroke()
fill(this.groupColor)
circle(this.x, this.y, this.diameter)
}
changeColor(newColor){
this.groupColor = newColor
}
}
class Centroid{
constructor(xPosition, yPosition, cColor, gColor){
this.x = xPosition
this.y = yPosition
this.groupXCoord = []
this.groupYCoord = []
this.centroidColor = cColor
this.groupColor = gColor
this.sideWidth = 20
}
show(){
noStroke()
fill(this.centroidColor)
rect(this.x, this.y, this.sideWidth, this.sideWidth)
}
changeCoords(newX, newY){
this.x = newX
this.y = newY
this.groupXCoord = []
this.groupYCoord = []
}
}
const generatePoints = (leftLimit, rightLimit, quantity, gColor) => {
const points = []
for (let i = 0; i < quantity; i++){
let x = floor(random(leftLimit, rightLimit))
let y = floor(random(leftLimit, rightLimit))
points.push(new DataPoint(x, y, gColor))
}
return points
}
const generateCentroid = (leftLimit, rightLimit, cColor, gColor) => {
const x = floor(random(leftLimit, rightLimit))
const y = floor(random(leftLimit, rightLimit))
return new Centroid(x, y, cColor, gColor)
}
const recalculateCentroids = (centroids) => {
let noMove = true
centroids.forEach(centroid => {
if (centroid.groupXCoord.length > 0){
let xSum = 0
let ySum = 0
for (let i = 0; i < centroid.groupXCoord.length; i++) {
xSum += centroid.groupXCoord[i];
ySum += centroid.groupYCoord[i];
}
let newX = floor(xSum / centroid.groupXCoord.length)
let newY = floor(ySum / centroid.groupYCoord.length)
if (newX === centroid.x && newY === centroid.y) noMove = noMove && true
else noMove = noMove && false
centroid.changeCoords(newX, newY)
}
})
return noMove
}
const findGroup = (dataPoint) => {
let currentGroup = 0
let minDist = euclidianDistance(dataPoint, centroids[0])
for (let i = 1; i < centroids.length; i++){
let newDist = euclidianDistance(dataPoint, centroids[i])
if (newDist < minDist){
minDist = newDist
currentGroup = i
}
}
dataPoint.changeColor(centroids[currentGroup].groupColor)
centroids[currentGroup].groupXCoord.push(dataPoint.x)
centroids[currentGroup].groupYCoord.push(dataPoint.y)
}
function setup() {
createCanvas(400, 400);
background(80);
frameRate(5);
nClusters = 3
nPoints = 75
dataPoints = [generatePoints(0, 140, 25, 'lightgray'), generatePoints(130, 250, 25, 'lightgray'), generatePoints(240, 390, 25, 'lightgray')]
centroids[0] = generateCentroid(0, 350, 'red', 'tomato')
centroids[1] = generateCentroid(0, 350, 'lime', 'limegreen')
centroids[2] = generateCentroid(0, 350, 'blue', 'dodgerblue')
dataPoints.forEach(point => point.show())
centroids.forEach(point => point.show())
counter = -1
}
function draw() {
background(80);
if (!stop){
if (counter === -1){
counter += 1
dataPoints.forEach(point => point.changeColor('lightgray'))
}
else if (counter < nPoints) {
findGroup(dataPoints[counter])
counter += 1
}
else {
counter = -1
stop = recalculateCentroids(centroids)
}
}
dataPoints.forEach(point => point.show())
centroids.forEach(point => point.show())
}