|
|
|
@ -10,6 +10,8 @@ import { rgbToCss, getRgbFromIndex } from '../utils/color.js'; |
|
|
|
import { getRevolution } from '../utils/group.js'; |
|
|
|
import { getRevolution } from '../utils/group.js'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const getDistance = (v1, v2) => { |
|
|
|
const getDistance = (v1, v2) => { |
|
|
|
if (!v1 || !v2) return Infinity; |
|
|
|
if (!v1 || !v2) return Infinity; |
|
|
|
return Math.sqrt( |
|
|
|
return Math.sqrt( |
|
|
|
@ -28,7 +30,10 @@ export default function Graph({results}){ |
|
|
|
// const [showContent, setShowContent]=useState(true); |
|
|
|
// const [showContent, setShowContent]=useState(true); |
|
|
|
// const [showKeyword, setShowKeyword]=useState(false); |
|
|
|
// const [showKeyword, setShowKeyword]=useState(false); |
|
|
|
|
|
|
|
|
|
|
|
const { showContent, contentType, showKeywords, showLines, textToShow, drawDistance, distToKeywords, keywordColor, useAnimation } = useControls({ |
|
|
|
const { showContent, contentType, showKeywords, showLines, textToShow, drawDistance, |
|
|
|
|
|
|
|
distToKeywords, keywordColor, useAnimation, |
|
|
|
|
|
|
|
maxGroupMembers, minGroupMembers, |
|
|
|
|
|
|
|
} = useControls({ |
|
|
|
showContent: { value: true }, |
|
|
|
showContent: { value: true }, |
|
|
|
contentType: { options: Object.values(PointContentType), value: PointContentType.Teaser }, |
|
|
|
contentType: { options: Object.values(PointContentType), value: PointContentType.Teaser }, |
|
|
|
showKeywords: { value: false }, |
|
|
|
showKeywords: { value: false }, |
|
|
|
@ -38,6 +43,8 @@ export default function Graph({results}){ |
|
|
|
keywordColor: { value: true }, |
|
|
|
keywordColor: { value: true }, |
|
|
|
distToKeywords: { value: 3, min: 0.1, max: 10, step: 0.01 }, |
|
|
|
distToKeywords: { value: 3, min: 0.1, max: 10, step: 0.01 }, |
|
|
|
useAnimation: {value:false}, |
|
|
|
useAnimation: {value:false}, |
|
|
|
|
|
|
|
maxGroupMembers: { value: 30, min: 1, max: 100 }, |
|
|
|
|
|
|
|
minGroupMembers: { value: 10, min: 1, max: 50 }, |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -106,32 +113,53 @@ export default function Graph({results}){ |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// --- STEP 2: Force Assignment for Empty Groups --- |
|
|
|
|
|
|
|
keywords.forEach(kw => { |
|
|
|
|
|
|
|
if (groupCounts[kw.id] === 0) { |
|
|
|
|
|
|
|
// Find the nearest data point that isn't a keyword itself |
|
|
|
|
|
|
|
let nearestPoint = null; |
|
|
|
|
|
|
|
let minDocDist = Infinity; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
results.forEach((res, idx) => { |
|
|
|
console.log("Initial group counts:", groupCounts); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Object.entries(groupCounts).forEach(([kwId, count]) => { |
|
|
|
|
|
|
|
// console.log(`Group ${kwId} has ${count} points assigned.`); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(count>=minGroupMembers && count<=maxGroupMembers){ |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(count<minGroupMembers){ |
|
|
|
|
|
|
|
// find least distant points to this keyword and assign until minGroupMembers is reached |
|
|
|
|
|
|
|
let nearestPoints=Array(minGroupMembers - count).fill(null); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
results.forEach(res => { |
|
|
|
if (res.type === 'keyword') return; |
|
|
|
if (res.type === 'keyword') return; |
|
|
|
|
|
|
|
const d = res.payload?.group?.find(g => g.id === parseInt(kwId))?.distance || Infinity; |
|
|
|
// Calculate distance in vector space (using the embedding/vector) |
|
|
|
if(d < distToKeywords && (!nearestPoints.some(p => p && p.id === res.id))) { |
|
|
|
const d = getDistance(res.vector, kw.vector); |
|
|
|
nearestPoints.push({...res ,d}); |
|
|
|
if (d < minDocDist) { |
|
|
|
|
|
|
|
minDocDist = d; |
|
|
|
|
|
|
|
nearestPoint = res; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// Re-assign the nearest point to this keyword |
|
|
|
nearestPoints = nearestPoints.filter(p => p !== null).slice(0, minGroupMembers - count); |
|
|
|
if (nearestPoint) { |
|
|
|
|
|
|
|
console.log(`Force assigning point ${nearestPoint.id} to empty group ${kw.id}`); |
|
|
|
nearestPoints.forEach(p => { |
|
|
|
nearestPoint.payload.group = [{ id: kw.id, distance: minDocDist }]; |
|
|
|
// console.log(`Assigning point ${p.id} to group ${kwId} to meet minGroupMembers.`); |
|
|
|
groupCounts[kw.id]++; |
|
|
|
p.payload.group = [{ id: kwId, distance: p.d }]; |
|
|
|
} |
|
|
|
groupCounts[kwId]++; |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(count>maxGroupMembers){ |
|
|
|
|
|
|
|
// find most distant points to this keyword and unassign until maxGroupMembers is reached |
|
|
|
|
|
|
|
let farthestPoints=results.filter(res => res.type !== 'keyword' && res.payload?.group?.[0]?.id === parseInt(kwId)) |
|
|
|
|
|
|
|
.sort((a,b) => (b.payload.group[0].distance || Infinity) - (a.payload.group[0].distance || Infinity)) |
|
|
|
|
|
|
|
.slice(0, count - maxGroupMembers); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
farthestPoints.forEach(p => { |
|
|
|
|
|
|
|
// console.log(`Unassigning point ${p.id} from group ${kwId} to meet maxGroupMembers.`); |
|
|
|
|
|
|
|
p.payload.group = p.payload.group.filter(g => g.id !== parseInt(kwId)); |
|
|
|
|
|
|
|
groupCounts[kwId]--; |
|
|
|
|
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
console.log("Final group counts after adjustment:", groupCounts); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let i=0; |
|
|
|
let i=0; |
|
|
|
@ -244,10 +272,10 @@ export default function Graph({results}){ |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
generateLinesFromPoints(points, drawDistance).then(newLines=>{ |
|
|
|
// generateLinesFromPoints(points, drawDistance).then(newLines=>{ |
|
|
|
console.log("Lines updated due to drawDistance change:", newLines); |
|
|
|
// console.log("Lines updated due to drawDistance change:", newLines); |
|
|
|
setLines(newLines); |
|
|
|
// setLines(newLines); |
|
|
|
}); |
|
|
|
// }); |
|
|
|
|
|
|
|
|
|
|
|
},[drawDistance]); |
|
|
|
},[drawDistance]); |
|
|
|
|
|
|
|
|
|
|
|
@ -266,10 +294,10 @@ export default function Graph({results}){ |
|
|
|
console.log("3D Points:", newPoints); |
|
|
|
console.log("3D Points:", newPoints); |
|
|
|
setPoints(newPoints); |
|
|
|
setPoints(newPoints); |
|
|
|
|
|
|
|
|
|
|
|
generateLinesFromPoints(newPoints, drawDistance).then(newLines=>{ |
|
|
|
// generateLinesFromPoints(newPoints, drawDistance).then(newLines=>{ |
|
|
|
console.log("Lines:", newLines); |
|
|
|
// console.log("Lines:", newLines); |
|
|
|
setLines(newLines); |
|
|
|
// setLines(newLines); |
|
|
|
}); |
|
|
|
// }); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|