Skip to content

Commit ccb463e

Browse files
committed
not working
1 parent 83250c1 commit ccb463e

File tree

5 files changed

+181
-90
lines changed

5 files changed

+181
-90
lines changed

package-lock.json

Lines changed: 45 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/compass-vector-embedding-visualizer/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"@leafygreen-ui/tooltip": "^13.0.12",
5353
"@types/plotly.js": "^3.0.0",
5454
"ml-pca": "^4.1.1",
55+
"mongodb": "^6.16.0",
5556
"plotly.js": "^3.0.1",
5657
"react": "^17.0.2",
5758
"react-dom": "^17.0.2"
@@ -65,6 +66,7 @@
6566
"@types/chai": "^4.2.21",
6667
"@types/chai-dom": "^0.0.10",
6768
"@types/mocha": "^9.0.0",
69+
"@types/mongodb": "^4.0.6",
6870
"@types/react": "^17.0.5",
6971
"@types/react-dom": "^17.0.10",
7072
"@types/sinon-chai": "^3.2.5",
@@ -74,7 +76,7 @@
7476
"mocha": "^10.2.0",
7577
"nyc": "^15.1.0",
7678
"sinon": "^17.0.1",
77-
"typescript": "^5.0.4",
79+
"typescript": "^5.8.3",
7880
"xvfb-maybe": "^0.2.1"
7981
},
8082
"is_compass_plugin": true

packages/compass-vector-embedding-visualizer/src/components/vector-visualizer.tsx

Lines changed: 105 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,32 @@
11
import React, { useEffect, useState } from 'react';
22
import Plotly from 'plotly.js';
3+
const PCA = require('ml-pca');
4+
import { Binary } from 'mongodb';
35

4-
type HoverInfo = {
5-
x: number;
6-
y: number;
7-
text: string;
8-
} | null;
6+
type HoverInfo = { x: number; y: number; text: string } | null;
97

10-
export const VectorVisualizer: React.FC = () => {
8+
export interface VectorVisualizerProps {
9+
dataService: {
10+
find: (
11+
ns: string,
12+
filter: Record<string, unknown>,
13+
options?: { limit?: number }
14+
) => Promise<any[]>;
15+
};
16+
collection: { namespace: string };
17+
}
18+
19+
function normalizeTo2D(vectors: Binary[]): { x: number; y: number }[] {
20+
const raw = vectors.map((v) => Array.from(v.toFloat32Array()));
21+
const pca = new PCA(raw);
22+
const reduced = pca.predict(raw, { nComponents: 2 }).to2DArray();
23+
return reduced.map(([x, y]: [number, number]) => ({ x, y }));
24+
}
25+
26+
export const VectorVisualizer: React.FC<VectorVisualizerProps> = ({
27+
dataService,
28+
collection,
29+
}) => {
1130
const [hoverInfo, setHoverInfo] = useState<HoverInfo>(null);
1231

1332
useEffect(() => {
@@ -17,77 +36,93 @@ export const VectorVisualizer: React.FC = () => {
1736
let isMounted = true;
1837

1938
const plot = async () => {
20-
await Plotly.newPlot(
21-
container,
22-
[
23-
{
24-
x: [1, 2, 3, 4, 5],
25-
y: [10, 15, 13, 17, 12],
26-
mode: 'markers',
27-
type: 'scatter',
28-
name: 'baskd',
29-
text: ['doc1', 'doc2', 'doc3', 'doc4', 'doc5'],
30-
hoverinfo: 'none',
31-
marker: {
32-
size: 15,
33-
color: 'teal',
34-
line: { width: 1, color: '#fff' },
39+
try {
40+
const ns = collection?.namespace;
41+
if (!ns || !dataService) return;
42+
43+
const docs = await dataService.find(ns, {}, { limit: 1000 });
44+
const vectors = docs.map((doc) => doc.review_vec).filter(Boolean);
45+
46+
if (!vectors.length) return;
47+
48+
const points = normalizeTo2D(vectors);
49+
50+
await Plotly.newPlot(
51+
container,
52+
[
53+
{
54+
x: points.map((p) => p.x),
55+
y: points.map((p) => p.y),
56+
mode: 'markers',
57+
type: 'scatter',
58+
text: docs.map((doc) => doc.review || '[no text]'),
59+
hoverinfo: 'none',
60+
marker: {
61+
size: 12,
62+
color: 'teal',
63+
line: { width: 1, color: '#fff' },
64+
},
3565
},
66+
],
67+
{
68+
hovermode: 'closest',
69+
margin: { l: 40, r: 10, t: 30, b: 30 },
70+
plot_bgcolor: '#f9f9f9',
71+
paper_bgcolor: '#f9f9f9',
3672
},
37-
],
38-
{
39-
margin: { l: 40, r: 10, t: 40, b: 40 },
40-
hovermode: 'closest',
41-
hoverdistance: 30,
42-
dragmode: 'zoom',
43-
plot_bgcolor: '#f7f7f7',
44-
paper_bgcolor: '#f7f7f7',
45-
xaxis: { gridcolor: '#e0e0e0' },
46-
yaxis: { gridcolor: '#e0e0e0' },
47-
},
48-
{ responsive: true }
49-
);
50-
51-
const handleHover = (data: any) => {
52-
const point = data.points?.[0];
53-
if (!point) return;
54-
55-
const containerRect = container.getBoundingClientRect();
56-
const relX = data.event.clientX - containerRect.left;
57-
const relY = data.event.clientY - containerRect.top;
58-
59-
if (isMounted) {
60-
setHoverInfo({ x: relX, y: relY, text: point.text });
61-
}
62-
};
63-
64-
const handleUnhover = () => {
65-
if (isMounted) {
66-
setHoverInfo(null);
67-
}
68-
};
69-
70-
container.addEventListener('plotly_hover', handleHover);
71-
container.addEventListener('plotly_unhover', handleUnhover);
72-
73-
// Cleanup
74-
return () => {
75-
isMounted = false;
76-
container.removeEventListener('plotly_hover', handleHover);
77-
container.removeEventListener('plotly_unhover', handleUnhover);
78-
};
73+
{ responsive: true }
74+
);
75+
76+
const handleHover = (event: Event) => {
77+
const e = event as CustomEvent<{
78+
points: { text: string }[];
79+
event: MouseEvent;
80+
}>;
81+
82+
const point = e.detail?.points?.[0];
83+
const mouse = e.detail?.event;
84+
if (!point || !mouse) return;
85+
86+
const rect = container.getBoundingClientRect();
87+
setHoverInfo({
88+
x: mouse.clientX - rect.left,
89+
y: mouse.clientY - rect.top,
90+
text: point.text,
91+
});
92+
};
93+
94+
const handleUnhover = () => setHoverInfo(null);
95+
96+
container.addEventListener(
97+
'plotly_hover',
98+
handleHover as EventListener
99+
);
100+
container.addEventListener(
101+
'plotly_unhover',
102+
handleUnhover as EventListener
103+
);
104+
105+
return () => {
106+
container.removeEventListener(
107+
'plotly_hover',
108+
handleHover as EventListener
109+
);
110+
container.removeEventListener(
111+
'plotly_unhover',
112+
handleUnhover as EventListener
113+
);
114+
};
115+
} catch (err) {
116+
console.error('VectorVisualizer error:', err);
117+
}
79118
};
80119

81-
let cleanup: (() => void) | undefined;
82-
void plot().then((c) => {
83-
if (typeof c === 'function') cleanup = c;
84-
});
120+
void plot();
85121

86122
return () => {
87123
isMounted = false;
88-
if (cleanup) cleanup();
89124
};
90-
}, []);
125+
}, [collection?.namespace, dataService]);
91126

92127
return (
93128
<div style={{ position: 'relative', width: '100%', height: '100%' }}>
@@ -103,8 +138,8 @@ export const VectorVisualizer: React.FC = () => {
103138
padding: '4px 8px',
104139
borderRadius: 4,
105140
pointerEvents: 'none',
106-
whiteSpace: 'nowrap',
107141
zIndex: 1000,
142+
whiteSpace: 'nowrap',
108143
}}
109144
>
110145
{hoverInfo.text}

0 commit comments

Comments
 (0)