Skip to content

Commit 621ffbc

Browse files
Add interactive HTML visualizations excluded by gitignore
The *.html gitignore rule was preventing spd_cone_interactive.html and spd_manifold_eeg.html from being tracked. Added an exception for docs/source/_static/*.html.
1 parent 1c25392 commit 621ffbc

File tree

3 files changed

+4038
-0
lines changed

3 files changed

+4038
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ doc/samples
4848
cover
4949
*.html
5050
!docs/source/_templates/*.html
51+
!docs/source/_static/*.html
5152

5253
*.orig
5354

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
5+
<style>
6+
body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; }
7+
#plot { width: 100%; height: 100%; }
8+
</style>
9+
</head>
10+
<body>
11+
<div id="plot"></div>
12+
<script>
13+
// Create mesh for the cone boundary (det = 0)
14+
// For 2x2 SPD matrix [[a,b],[b,c]], boundary is b² = ac
15+
const n = 40;
16+
17+
// Parametric surface: use (a, c) as parameters, b = ±sqrt(ac) on boundary
18+
const aVals = [], cVals = [];
19+
for (let i = 0; i < n; i++) {
20+
aVals.push(0.01 + (3.0 * i / (n - 1)));
21+
cVals.push(0.01 + (3.0 * i / (n - 1)));
22+
}
23+
24+
// Upper boundary surface (b = +sqrt(ac))
25+
const xUpper = [], yUpper = [], zUpper = [];
26+
for (let i = 0; i < n; i++) {
27+
const xRow = [], yRow = [], zRow = [];
28+
for (let j = 0; j < n; j++) {
29+
const a = aVals[i];
30+
const c = cVals[j];
31+
xRow.push(a);
32+
yRow.push(Math.sqrt(a * c));
33+
zRow.push(c);
34+
}
35+
xUpper.push(xRow);
36+
yUpper.push(yRow);
37+
zUpper.push(zRow);
38+
}
39+
40+
// Lower boundary surface (b = -sqrt(ac))
41+
const xLower = [], yLower = [], zLower = [];
42+
for (let i = 0; i < n; i++) {
43+
const xRow = [], yRow = [], zRow = [];
44+
for (let j = 0; j < n; j++) {
45+
const a = aVals[i];
46+
const c = cVals[j];
47+
xRow.push(a);
48+
yRow.push(-Math.sqrt(a * c));
49+
zRow.push(c);
50+
}
51+
xLower.push(xRow);
52+
yLower.push(yRow);
53+
zLower.push(zRow);
54+
}
55+
56+
// Generate random SPD points INSIDE the cone (det > 0, so |b| < sqrt(ac))
57+
// Using mulberry32 PRNG for reproducibility
58+
function mulberry32(a) {
59+
return function() {
60+
var t = a += 0x6D2B79F5;
61+
t = Math.imul(t ^ t >>> 15, t | 1);
62+
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
63+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
64+
}
65+
}
66+
67+
const rand = mulberry32(42);
68+
const spdX = [], spdY = [], spdZ = [];
69+
for (let i = 0; i < 80; i++) {
70+
const a = 0.3 + rand() * 2.4;
71+
const c = 0.3 + rand() * 2.4;
72+
const bMax = Math.sqrt(a * c) * 0.85; // Stay well inside cone
73+
const b = (rand() * 2 - 1) * bMax;
74+
spdX.push(a);
75+
spdY.push(b);
76+
spdZ.push(c);
77+
}
78+
79+
const surfaceUpper = {
80+
type: 'surface',
81+
x: xUpper,
82+
y: yUpper,
83+
z: zUpper,
84+
opacity: 0.35,
85+
colorscale: [[0, 'rgb(79, 140, 255)'], [1, 'rgb(79, 140, 255)']],
86+
showscale: false,
87+
name: 'Cone boundary (det=0)',
88+
hoverinfo: 'skip'
89+
};
90+
91+
const surfaceLower = {
92+
type: 'surface',
93+
x: xLower,
94+
y: yLower,
95+
z: zLower,
96+
opacity: 0.35,
97+
colorscale: [[0, 'rgb(79, 140, 255)'], [1, 'rgb(79, 140, 255)']],
98+
showscale: false,
99+
name: 'Cone boundary',
100+
hoverinfo: 'skip',
101+
showlegend: false
102+
};
103+
104+
const spdPoints = {
105+
type: 'scatter3d',
106+
mode: 'markers',
107+
x: spdX,
108+
y: spdY,
109+
z: spdZ,
110+
marker: {
111+
size: 4,
112+
color: 'rgb(238, 76, 44)',
113+
opacity: 0.9
114+
},
115+
name: 'SPD matrices (det > 0)',
116+
hovertemplate: 'a=%{x:.2f}<br>b=%{y:.2f}<br>c=%{z:.2f}<br>det=%{customdata:.2f}<extra></extra>',
117+
customdata: spdX.map((a, i) => a * spdZ[i] - spdY[i] * spdY[i])
118+
};
119+
120+
const layout = {
121+
title: {
122+
text: '<b>SPD Manifold as a Cone in 3D</b><br><span style="font-size:13px;color:#666">2×2 symmetric matrices: SPD region is inside the cone (det > 0)</span>',
123+
font: { size: 18 }
124+
},
125+
scene: {
126+
xaxis: { title: 'a (diagonal)', range: [0, 3.2] },
127+
yaxis: { title: 'b (off-diagonal)', range: [-3, 3] },
128+
zaxis: { title: 'c (diagonal)', range: [0, 3.2] },
129+
camera: {
130+
eye: { x: 1.8, y: 1.4, z: 1.0 }
131+
},
132+
aspectmode: 'cube'
133+
},
134+
margin: { l: 10, r: 10, t: 60, b: 10 },
135+
legend: {
136+
x: 0.01,
137+
y: 0.99,
138+
bgcolor: 'rgba(255,255,255,0.85)',
139+
bordercolor: 'rgba(0,0,0,0.1)',
140+
borderwidth: 1
141+
},
142+
paper_bgcolor: 'rgba(0,0,0,0)',
143+
plot_bgcolor: 'rgba(0,0,0,0)'
144+
};
145+
146+
Plotly.newPlot('plot', [surfaceUpper, surfaceLower, spdPoints], layout, {responsive: true});
147+
</script>
148+
</body>
149+
</html>

docs/source/_static/spd_manifold_eeg.html

Lines changed: 3888 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)