Spaces:
Running
Running
updated code
Browse files- ._complete-statistics +0 -0
- complete-statistics/app.js +454 -0
- complete-statistics/index.html +0 -0
- complete-statistics/style.css +1631 -0
- ml_complete-all-topics/app.js +334 -0
- ml_complete-all-topics/index.html +511 -0
._complete-statistics
ADDED
|
Binary file (4.1 kB). View file
|
|
|
complete-statistics/app.js
ADDED
|
@@ -0,0 +1,454 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// ===== CONFIGURATION & CONSTANTS =====
|
| 2 |
+
const COLORS = {
|
| 3 |
+
primary: '#4a90e2',
|
| 4 |
+
cyan: '#64ffda',
|
| 5 |
+
orange: '#ff6b6b',
|
| 6 |
+
green: '#51cf66',
|
| 7 |
+
background: '#0f3460',
|
| 8 |
+
text: '#e1e1e1',
|
| 9 |
+
textSecondary: '#a0a0a0'
|
| 10 |
+
};
|
| 11 |
+
|
| 12 |
+
const chartColors = ['#1FB8CD', '#FFC185', '#B4413C', '#ECEBD5', '#5D878F', '#DB4545', '#D2BA4C', '#964325', '#944454', '#13343B'];
|
| 13 |
+
|
| 14 |
+
// ===== STATE MANAGEMENT =====
|
| 15 |
+
let currentTopic = 1;
|
| 16 |
+
let animationFrames = {};
|
| 17 |
+
|
| 18 |
+
// ===== INITIALIZATION =====
|
| 19 |
+
document.addEventListener('DOMContentLoaded', () => {
|
| 20 |
+
initNavigation();
|
| 21 |
+
initInteractiveElements();
|
| 22 |
+
setupScrollObserver();
|
| 23 |
+
initializeAllVisualizations();
|
| 24 |
+
});
|
| 25 |
+
|
| 26 |
+
// ===== NAVIGATION =====
|
| 27 |
+
function initNavigation() {
|
| 28 |
+
// Mobile menu toggle
|
| 29 |
+
const mobileMenuBtn = document.getElementById('mobileMenuBtn');
|
| 30 |
+
const sidebar = document.getElementById('sidebar');
|
| 31 |
+
|
| 32 |
+
if (mobileMenuBtn) {
|
| 33 |
+
mobileMenuBtn.addEventListener('click', () => {
|
| 34 |
+
sidebar.classList.toggle('active');
|
| 35 |
+
});
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
// Topic link navigation
|
| 39 |
+
const topicLinks = document.querySelectorAll('.topic-link');
|
| 40 |
+
topicLinks.forEach(link => {
|
| 41 |
+
link.addEventListener('click', (e) => {
|
| 42 |
+
e.preventDefault();
|
| 43 |
+
const topicId = link.getAttribute('data-topic');
|
| 44 |
+
const target = document.getElementById(`topic-${topicId}`);
|
| 45 |
+
|
| 46 |
+
if (target) {
|
| 47 |
+
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
| 48 |
+
updateActiveLink(topicId);
|
| 49 |
+
|
| 50 |
+
// Close mobile menu if open
|
| 51 |
+
if (window.innerWidth <= 1024) {
|
| 52 |
+
sidebar.classList.remove('active');
|
| 53 |
+
}
|
| 54 |
+
}
|
| 55 |
+
});
|
| 56 |
+
});
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
function updateActiveLink(topicId) {
|
| 60 |
+
document.querySelectorAll('.topic-link').forEach(link => {
|
| 61 |
+
link.classList.remove('active');
|
| 62 |
+
});
|
| 63 |
+
const activeLink = document.querySelector(`[data-topic="${topicId}"]`);
|
| 64 |
+
if (activeLink) {
|
| 65 |
+
activeLink.classList.add('active');
|
| 66 |
+
}
|
| 67 |
+
currentTopic = parseInt(topicId);
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
// ===== SCROLL OBSERVER =====
|
| 71 |
+
function setupScrollObserver() {
|
| 72 |
+
const options = {
|
| 73 |
+
root: null,
|
| 74 |
+
rootMargin: '-100px',
|
| 75 |
+
threshold: 0.3
|
| 76 |
+
};
|
| 77 |
+
|
| 78 |
+
const observer = new IntersectionObserver((entries) => {
|
| 79 |
+
entries.forEach(entry => {
|
| 80 |
+
if (entry.isIntersecting) {
|
| 81 |
+
const topicId = entry.target.id.split('-')[1];
|
| 82 |
+
updateActiveLink(topicId);
|
| 83 |
+
}
|
| 84 |
+
});
|
| 85 |
+
}, options);
|
| 86 |
+
|
| 87 |
+
document.querySelectorAll('.topic-section').forEach(section => {
|
| 88 |
+
observer.observe(section);
|
| 89 |
+
});
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
// ===== CANVAS UTILITIES =====
|
| 93 |
+
function clearCanvas(ctx, canvas) {
|
| 94 |
+
ctx.fillStyle = COLORS.background;
|
| 95 |
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
function drawText(ctx, text, x, y, fontSize = 14, color = COLORS.text, align = 'center') {
|
| 99 |
+
ctx.fillStyle = color;
|
| 100 |
+
ctx.font = `${fontSize}px 'Segoe UI', sans-serif`;
|
| 101 |
+
ctx.textAlign = align;
|
| 102 |
+
ctx.fillText(text, x, y);
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
function drawCircle(ctx, x, y, radius, color, filled = true) {
|
| 106 |
+
ctx.beginPath();
|
| 107 |
+
ctx.arc(x, y, radius, 0, Math.PI * 2);
|
| 108 |
+
if (filled) {
|
| 109 |
+
ctx.fillStyle = color;
|
| 110 |
+
ctx.fill();
|
| 111 |
+
} else {
|
| 112 |
+
ctx.strokeStyle = color;
|
| 113 |
+
ctx.lineWidth = 2;
|
| 114 |
+
ctx.stroke();
|
| 115 |
+
}
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
function drawLine(ctx, x1, y1, x2, y2, color = COLORS.text, width = 1) {
|
| 119 |
+
ctx.beginPath();
|
| 120 |
+
ctx.moveTo(x1, y1);
|
| 121 |
+
ctx.lineTo(x2, y2);
|
| 122 |
+
ctx.strokeStyle = color;
|
| 123 |
+
ctx.lineWidth = width;
|
| 124 |
+
ctx.stroke();
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
function drawRect(ctx, x, y, width, height, color, filled = true) {
|
| 128 |
+
if (filled) {
|
| 129 |
+
ctx.fillStyle = color;
|
| 130 |
+
ctx.fillRect(x, y, width, height);
|
| 131 |
+
} else {
|
| 132 |
+
ctx.strokeStyle = color;
|
| 133 |
+
ctx.lineWidth = 2;
|
| 134 |
+
ctx.strokeRect(x, y, width, height);
|
| 135 |
+
}
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
// ===== STATISTICAL CALCULATIONS =====
|
| 139 |
+
function calculateMean(data) {
|
| 140 |
+
return data.reduce((sum, val) => sum + val, 0) / data.length;
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
function calculateMedian(data) {
|
| 144 |
+
const sorted = [...data].sort((a, b) => a - b);
|
| 145 |
+
const mid = Math.floor(sorted.length / 2);
|
| 146 |
+
return sorted.length % 2 === 0
|
| 147 |
+
? (sorted[mid - 1] + sorted[mid]) / 2
|
| 148 |
+
: sorted[mid];
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
function calculateMode(data) {
|
| 152 |
+
const frequency = {};
|
| 153 |
+
let maxFreq = 0;
|
| 154 |
+
|
| 155 |
+
data.forEach(val => {
|
| 156 |
+
frequency[val] = (frequency[val] || 0) + 1;
|
| 157 |
+
maxFreq = Math.max(maxFreq, frequency[val]);
|
| 158 |
+
});
|
| 159 |
+
|
| 160 |
+
if (maxFreq === 1) return 'None';
|
| 161 |
+
|
| 162 |
+
const modes = Object.keys(frequency).filter(key => frequency[key] === maxFreq);
|
| 163 |
+
return modes.join(', ');
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
function calculateVariance(data, isSample = true) {
|
| 167 |
+
const mean = calculateMean(data);
|
| 168 |
+
const squaredDiffs = data.map(val => Math.pow(val - mean, 2));
|
| 169 |
+
const divisor = isSample ? data.length - 1 : data.length;
|
| 170 |
+
return squaredDiffs.reduce((sum, val) => sum + val, 0) / divisor;
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
function calculateStdDev(data, isSample = true) {
|
| 174 |
+
return Math.sqrt(calculateVariance(data, isSample));
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
function calculateQuartiles(data) {
|
| 178 |
+
const sorted = [...data].sort((a, b) => a - b);
|
| 179 |
+
const q2 = calculateMedian(sorted);
|
| 180 |
+
const midIndex = Math.floor(sorted.length / 2);
|
| 181 |
+
|
| 182 |
+
const lowerHalf = sorted.length % 2 === 0
|
| 183 |
+
? sorted.slice(0, midIndex)
|
| 184 |
+
: sorted.slice(0, midIndex);
|
| 185 |
+
const upperHalf = sorted.length % 2 === 0
|
| 186 |
+
? sorted.slice(midIndex)
|
| 187 |
+
: sorted.slice(midIndex + 1);
|
| 188 |
+
|
| 189 |
+
const q1 = calculateMedian(lowerHalf);
|
| 190 |
+
const q3 = calculateMedian(upperHalf);
|
| 191 |
+
|
| 192 |
+
return { q1, q2, q3 };
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
function calculateIQR(data) {
|
| 196 |
+
const { q1, q3 } = calculateQuartiles(data);
|
| 197 |
+
const iqr = q3 - q1;
|
| 198 |
+
const lowerFence = q1 - 1.5 * iqr;
|
| 199 |
+
const upperFence = q3 + 1.5 * iqr;
|
| 200 |
+
|
| 201 |
+
return { q1, q3, iqr, lowerFence, upperFence };
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
function detectOutliers(data) {
|
| 205 |
+
const { lowerFence, upperFence } = calculateIQR(data);
|
| 206 |
+
return data.filter(val => val < lowerFence || val > upperFence);
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
function calculateCovariance(x, y) {
|
| 210 |
+
const meanX = calculateMean(x);
|
| 211 |
+
const meanY = calculateMean(y);
|
| 212 |
+
let sum = 0;
|
| 213 |
+
|
| 214 |
+
for (let i = 0; i < x.length; i++) {
|
| 215 |
+
sum += (x[i] - meanX) * (y[i] - meanY);
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
return sum / (x.length - 1);
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
function calculateCorrelation(x, y) {
|
| 222 |
+
const cov = calculateCovariance(x, y);
|
| 223 |
+
const stdX = calculateStdDev(x);
|
| 224 |
+
const stdY = calculateStdDev(y);
|
| 225 |
+
return cov / (stdX * stdY);
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
// ===== VISUALIZATION FUNCTIONS =====
|
| 229 |
+
|
| 230 |
+
// Population vs Sample Visualization
|
| 231 |
+
function initPopulationSampleViz() {
|
| 232 |
+
const canvas = document.getElementById('populationSampleCanvas');
|
| 233 |
+
if (!canvas) return;
|
| 234 |
+
|
| 235 |
+
const ctx = canvas.getContext('2d');
|
| 236 |
+
let population = [];
|
| 237 |
+
let sample = [];
|
| 238 |
+
let sampleSize = 30;
|
| 239 |
+
|
| 240 |
+
// Initialize population
|
| 241 |
+
for (let i = 0; i < 200; i++) {
|
| 242 |
+
population.push({
|
| 243 |
+
x: Math.random() * (canvas.width - 40) + 20,
|
| 244 |
+
y: Math.random() * (canvas.height - 40) + 20,
|
| 245 |
+
inSample: false
|
| 246 |
+
});
|
| 247 |
+
}
|
| 248 |
+
|
| 249 |
+
function draw() {
|
| 250 |
+
clearCanvas(ctx, canvas);
|
| 251 |
+
|
| 252 |
+
// Draw title
|
| 253 |
+
drawText(ctx, 'Population (All dots) vs Sample (Highlighted)', canvas.width / 2, 30, 16, COLORS.cyan);
|
| 254 |
+
|
| 255 |
+
// Draw population
|
| 256 |
+
population.forEach(point => {
|
| 257 |
+
const color = point.inSample ? COLORS.orange : COLORS.primary;
|
| 258 |
+
const radius = point.inSample ? 6 : 4;
|
| 259 |
+
drawCircle(ctx, point.x, point.y, radius, color);
|
| 260 |
+
});
|
| 261 |
+
|
| 262 |
+
// Draw statistics
|
| 263 |
+
const popCount = population.length;
|
| 264 |
+
const sampleCount = population.filter(p => p.inSample).length;
|
| 265 |
+
drawText(ctx, `Population Size: N = ${popCount}`, 150, canvas.height - 20, 14, COLORS.text, 'center');
|
| 266 |
+
drawText(ctx, `Sample Size: n = ${sampleCount}`, canvas.width - 150, canvas.height - 20, 14, COLORS.orange, 'center');
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
function takeSample() {
|
| 270 |
+
// Reset all
|
| 271 |
+
population.forEach(p => p.inSample = false);
|
| 272 |
+
|
| 273 |
+
// Randomly select sample
|
| 274 |
+
const shuffled = [...population].sort(() => Math.random() - 0.5);
|
| 275 |
+
for (let i = 0; i < Math.min(sampleSize, population.length); i++) {
|
| 276 |
+
shuffled[i].inSample = true;
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
draw();
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
// Event listeners
|
| 283 |
+
const sampleBtn = document.getElementById('sampleBtn');
|
| 284 |
+
const resetBtn = document.getElementById('resetPopBtn');
|
| 285 |
+
const sizeSlider = document.getElementById('sampleSizeSlider');
|
| 286 |
+
const sizeLabel = document.getElementById('sampleSizeLabel');
|
| 287 |
+
|
| 288 |
+
if (sampleBtn) {
|
| 289 |
+
sampleBtn.addEventListener('click', takeSample);
|
| 290 |
+
}
|
| 291 |
+
|
| 292 |
+
if (resetBtn) {
|
| 293 |
+
resetBtn.addEventListener('click', () => {
|
| 294 |
+
population.forEach(p => p.inSample = false);
|
| 295 |
+
draw();
|
| 296 |
+
});
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
if (sizeSlider) {
|
| 300 |
+
sizeSlider.addEventListener('input', (e) => {
|
| 301 |
+
sampleSize = parseInt(e.target.value);
|
| 302 |
+
if (sizeLabel) {
|
| 303 |
+
sizeLabel.textContent = sampleSize;
|
| 304 |
+
}
|
| 305 |
+
});
|
| 306 |
+
}
|
| 307 |
+
|
| 308 |
+
draw();
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
// Central Tendency Visualization
|
| 312 |
+
function initCentralTendencyViz() {
|
| 313 |
+
const canvas = document.getElementById('centralTendencyCanvas');
|
| 314 |
+
if (!canvas) return;
|
| 315 |
+
|
| 316 |
+
const ctx = canvas.getContext('2d');
|
| 317 |
+
let data = [10, 20, 30, 40, 50];
|
| 318 |
+
|
| 319 |
+
function parseInput(input) {
|
| 320 |
+
return input.split(',').map(s => parseFloat(s.trim())).filter(n => !isNaN(n));
|
| 321 |
+
}
|
| 322 |
+
|
| 323 |
+
function draw() {
|
| 324 |
+
clearCanvas(ctx, canvas);
|
| 325 |
+
|
| 326 |
+
if (data.length === 0) {
|
| 327 |
+
drawText(ctx, 'Please enter valid numbers', canvas.width / 2, canvas.height / 2, 16, COLORS.orange);
|
| 328 |
+
return;
|
| 329 |
+
}
|
| 330 |
+
|
| 331 |
+
const sorted = [...data].sort((a, b) => a - b);
|
| 332 |
+
const min = Math.min(...sorted);
|
| 333 |
+
const max = Math.max(...sorted);
|
| 334 |
+
const range = max - min || 1;
|
| 335 |
+
const padding = 80;
|
| 336 |
+
const width = canvas.width - 2 * padding;
|
| 337 |
+
|
| 338 |
+
// Calculate statistics
|
| 339 |
+
const mean = calculateMean(data);
|
| 340 |
+
const median = calculateMedian(data);
|
| 341 |
+
const mode = calculateMode(data);
|
| 342 |
+
|
| 343 |
+
// Update results display
|
| 344 |
+
document.getElementById('meanResult').textContent = mean.toFixed(2);
|
| 345 |
+
document.getElementById('medianResult').textContent = median.toFixed(2);
|
| 346 |
+
document.getElementById('modeResult').textContent = mode;
|
| 347 |
+
|
| 348 |
+
// Draw axis
|
| 349 |
+
const axisY = canvas.height / 2;
|
| 350 |
+
drawLine(ctx, padding, axisY, canvas.width - padding, axisY, COLORS.text, 2);
|
| 351 |
+
|
| 352 |
+
// Draw data points
|
| 353 |
+
sorted.forEach((val, idx) => {
|
| 354 |
+
const x = padding + ((val - min) / range) * width;
|
| 355 |
+
drawCircle(ctx, x, axisY, 8, COLORS.primary);
|
| 356 |
+
drawText(ctx, val.toString(), x, axisY + 30, 12, COLORS.text);
|
| 357 |
+
});
|
| 358 |
+
|
| 359 |
+
// Draw mean
|
| 360 |
+
const meanX = padding + ((mean - min) / range) * width;
|
| 361 |
+
drawLine(ctx, meanX, axisY - 60, meanX, axisY + 60, COLORS.cyan, 3);
|
| 362 |
+
drawText(ctx, `Mean: ${mean.toFixed(2)}`, meanX, axisY - 70, 14, COLORS.cyan);
|
| 363 |
+
|
| 364 |
+
// Draw median
|
| 365 |
+
const medianX = padding + ((median - min) / range) * width;
|
| 366 |
+
drawLine(ctx, medianX, axisY - 50, medianX, axisY + 50, COLORS.orange, 2);
|
| 367 |
+
drawText(ctx, `Median: ${median.toFixed(2)}`, medianX, axisY - 55, 12, COLORS.orange);
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
+
// Event listeners
|
| 371 |
+
const input = document.getElementById('centralTendencyInput');
|
| 372 |
+
const calcBtn = document.getElementById('calculateCentralBtn');
|
| 373 |
+
const randomBtn = document.getElementById('randomDataBtn');
|
| 374 |
+
|
| 375 |
+
if (calcBtn && input) {
|
| 376 |
+
calcBtn.addEventListener('click', () => {
|
| 377 |
+
data = parseInput(input.value);
|
| 378 |
+
draw();
|
| 379 |
+
});
|
| 380 |
+
}
|
| 381 |
+
|
| 382 |
+
if (randomBtn && input) {
|
| 383 |
+
randomBtn.addEventListener('click', () => {
|
| 384 |
+
data = Array.from({ length: 10 }, () => Math.floor(Math.random() * 100));
|
| 385 |
+
input.value = data.join(', ');
|
| 386 |
+
draw();
|
| 387 |
+
});
|
| 388 |
+
}
|
| 389 |
+
|
| 390 |
+
if (input) {
|
| 391 |
+
input.addEventListener('keypress', (e) => {
|
| 392 |
+
if (e.key === 'Enter') {
|
| 393 |
+
data = parseInput(input.value);
|
| 394 |
+
draw();
|
| 395 |
+
}
|
| 396 |
+
});
|
| 397 |
+
}
|
| 398 |
+
|
| 399 |
+
draw();
|
| 400 |
+
}
|
| 401 |
+
|
| 402 |
+
// ===== INITIALIZE ALL VISUALIZATIONS =====
|
| 403 |
+
function initializeAllVisualizations() {
|
| 404 |
+
// Topic 2: Population vs Sample
|
| 405 |
+
initPopulationSampleViz();
|
| 406 |
+
|
| 407 |
+
// Topic 5: Central Tendency
|
| 408 |
+
initCentralTendencyViz();
|
| 409 |
+
|
| 410 |
+
// Add more visualizations as needed
|
| 411 |
+
// Each topic with a canvas gets its own initialization function
|
| 412 |
+
}
|
| 413 |
+
|
| 414 |
+
// ===== INTERACTIVE ELEMENTS =====
|
| 415 |
+
function initInteractiveElements() {
|
| 416 |
+
// Add any additional interactive elements here
|
| 417 |
+
// Such as tooltips, modals, etc.
|
| 418 |
+
}
|
| 419 |
+
|
| 420 |
+
// ===== HELPER FUNCTIONS =====
|
| 421 |
+
function generateRandomData(count, min, max) {
|
| 422 |
+
return Array.from({ length: count }, () =>
|
| 423 |
+
Math.floor(Math.random() * (max - min + 1)) + min
|
| 424 |
+
);
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
function formatNumber(num, decimals = 2) {
|
| 428 |
+
return Number(num).toFixed(decimals);
|
| 429 |
+
}
|
| 430 |
+
|
| 431 |
+
// ===== ANIMATION LOOP =====
|
| 432 |
+
function startAnimation(canvasId, animationFunction) {
|
| 433 |
+
if (animationFrames[canvasId]) {
|
| 434 |
+
cancelAnimationFrame(animationFrames[canvasId]);
|
| 435 |
+
}
|
| 436 |
+
|
| 437 |
+
function animate() {
|
| 438 |
+
animationFunction();
|
| 439 |
+
animationFrames[canvasId] = requestAnimationFrame(animate);
|
| 440 |
+
}
|
| 441 |
+
|
| 442 |
+
animate();
|
| 443 |
+
}
|
| 444 |
+
|
| 445 |
+
function stopAnimation(canvasId) {
|
| 446 |
+
if (animationFrames[canvasId]) {
|
| 447 |
+
cancelAnimationFrame(animationFrames[canvasId]);
|
| 448 |
+
delete animationFrames[canvasId];
|
| 449 |
+
}
|
| 450 |
+
}
|
| 451 |
+
|
| 452 |
+
// ===== CONSOLE LOG =====
|
| 453 |
+
console.log('%cπ Statistics Mastery Platform Loaded', 'color: #64ffda; font-size: 16px; font-weight: bold;');
|
| 454 |
+
console.log('%cReady to explore 41 comprehensive statistics topics!', 'color: #4a90e2; font-size: 14px;');
|
complete-statistics/index.html
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
complete-statistics/style.css
ADDED
|
@@ -0,0 +1,1631 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
:root {
|
| 2 |
+
/* Primitive Color Tokens */
|
| 3 |
+
--color-white: rgba(255, 255, 255, 1);
|
| 4 |
+
--color-black: rgba(0, 0, 0, 1);
|
| 5 |
+
--color-cream-50: rgba(252, 252, 249, 1);
|
| 6 |
+
--color-cream-100: rgba(255, 255, 253, 1);
|
| 7 |
+
--color-gray-200: rgba(245, 245, 245, 1);
|
| 8 |
+
--color-gray-300: rgba(167, 169, 169, 1);
|
| 9 |
+
--color-gray-400: rgba(119, 124, 124, 1);
|
| 10 |
+
--color-slate-500: rgba(98, 108, 113, 1);
|
| 11 |
+
--color-brown-600: rgba(94, 82, 64, 1);
|
| 12 |
+
--color-charcoal-700: rgba(31, 33, 33, 1);
|
| 13 |
+
--color-charcoal-800: rgba(38, 40, 40, 1);
|
| 14 |
+
--color-slate-900: rgba(19, 52, 59, 1);
|
| 15 |
+
--color-teal-300: rgba(50, 184, 198, 1);
|
| 16 |
+
--color-teal-400: rgba(45, 166, 178, 1);
|
| 17 |
+
--color-teal-500: rgba(33, 128, 141, 1);
|
| 18 |
+
--color-teal-600: rgba(29, 116, 128, 1);
|
| 19 |
+
--color-teal-700: rgba(26, 104, 115, 1);
|
| 20 |
+
--color-teal-800: rgba(41, 150, 161, 1);
|
| 21 |
+
--color-red-400: rgba(255, 84, 89, 1);
|
| 22 |
+
--color-red-500: rgba(192, 21, 47, 1);
|
| 23 |
+
--color-orange-400: rgba(230, 129, 97, 1);
|
| 24 |
+
--color-orange-500: rgba(168, 75, 47, 1);
|
| 25 |
+
|
| 26 |
+
/* RGB versions for opacity control */
|
| 27 |
+
--color-brown-600-rgb: 94, 82, 64;
|
| 28 |
+
--color-teal-500-rgb: 33, 128, 141;
|
| 29 |
+
--color-slate-900-rgb: 19, 52, 59;
|
| 30 |
+
--color-slate-500-rgb: 98, 108, 113;
|
| 31 |
+
--color-red-500-rgb: 192, 21, 47;
|
| 32 |
+
--color-red-400-rgb: 255, 84, 89;
|
| 33 |
+
--color-orange-500-rgb: 168, 75, 47;
|
| 34 |
+
--color-orange-400-rgb: 230, 129, 97;
|
| 35 |
+
|
| 36 |
+
/* Background color tokens (Light Mode) */
|
| 37 |
+
--color-bg-1: rgba(59, 130, 246, 0.08); /* Light blue */
|
| 38 |
+
--color-bg-2: rgba(245, 158, 11, 0.08); /* Light yellow */
|
| 39 |
+
--color-bg-3: rgba(34, 197, 94, 0.08); /* Light green */
|
| 40 |
+
--color-bg-4: rgba(239, 68, 68, 0.08); /* Light red */
|
| 41 |
+
--color-bg-5: rgba(147, 51, 234, 0.08); /* Light purple */
|
| 42 |
+
--color-bg-6: rgba(249, 115, 22, 0.08); /* Light orange */
|
| 43 |
+
--color-bg-7: rgba(236, 72, 153, 0.08); /* Light pink */
|
| 44 |
+
--color-bg-8: rgba(6, 182, 212, 0.08); /* Light cyan */
|
| 45 |
+
|
| 46 |
+
/* Semantic Color Tokens (Light Mode) */
|
| 47 |
+
--color-background: var(--color-cream-50);
|
| 48 |
+
--color-surface: var(--color-cream-100);
|
| 49 |
+
--color-text: var(--color-slate-900);
|
| 50 |
+
--color-text-secondary: var(--color-slate-500);
|
| 51 |
+
--color-primary: var(--color-teal-500);
|
| 52 |
+
--color-primary-hover: var(--color-teal-600);
|
| 53 |
+
--color-primary-active: var(--color-teal-700);
|
| 54 |
+
--color-secondary: rgba(var(--color-brown-600-rgb), 0.12);
|
| 55 |
+
--color-secondary-hover: rgba(var(--color-brown-600-rgb), 0.2);
|
| 56 |
+
--color-secondary-active: rgba(var(--color-brown-600-rgb), 0.25);
|
| 57 |
+
--color-border: rgba(var(--color-brown-600-rgb), 0.2);
|
| 58 |
+
--color-btn-primary-text: var(--color-cream-50);
|
| 59 |
+
--color-card-border: rgba(var(--color-brown-600-rgb), 0.12);
|
| 60 |
+
--color-card-border-inner: rgba(var(--color-brown-600-rgb), 0.12);
|
| 61 |
+
--color-error: var(--color-red-500);
|
| 62 |
+
--color-success: var(--color-teal-500);
|
| 63 |
+
--color-warning: var(--color-orange-500);
|
| 64 |
+
--color-info: var(--color-slate-500);
|
| 65 |
+
--color-focus-ring: rgba(var(--color-teal-500-rgb), 0.4);
|
| 66 |
+
--color-select-caret: rgba(var(--color-slate-900-rgb), 0.8);
|
| 67 |
+
|
| 68 |
+
/* Common style patterns */
|
| 69 |
+
--focus-ring: 0 0 0 3px var(--color-focus-ring);
|
| 70 |
+
--focus-outline: 2px solid var(--color-primary);
|
| 71 |
+
--status-bg-opacity: 0.15;
|
| 72 |
+
--status-border-opacity: 0.25;
|
| 73 |
+
--select-caret-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23134252' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
|
| 74 |
+
--select-caret-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23f5f5f5' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
|
| 75 |
+
|
| 76 |
+
/* RGB versions for opacity control */
|
| 77 |
+
--color-success-rgb: 33, 128, 141;
|
| 78 |
+
--color-error-rgb: 192, 21, 47;
|
| 79 |
+
--color-warning-rgb: 168, 75, 47;
|
| 80 |
+
--color-info-rgb: 98, 108, 113;
|
| 81 |
+
|
| 82 |
+
/* Typography */
|
| 83 |
+
--font-family-base: "FKGroteskNeue", "Geist", "Inter", -apple-system,
|
| 84 |
+
BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
| 85 |
+
--font-family-mono: "Berkeley Mono", ui-monospace, SFMono-Regular, Menlo,
|
| 86 |
+
Monaco, Consolas, monospace;
|
| 87 |
+
--font-size-xs: 11px;
|
| 88 |
+
--font-size-sm: 12px;
|
| 89 |
+
--font-size-base: 14px;
|
| 90 |
+
--font-size-md: 14px;
|
| 91 |
+
--font-size-lg: 16px;
|
| 92 |
+
--font-size-xl: 18px;
|
| 93 |
+
--font-size-2xl: 20px;
|
| 94 |
+
--font-size-3xl: 24px;
|
| 95 |
+
--font-size-4xl: 30px;
|
| 96 |
+
--font-weight-normal: 400;
|
| 97 |
+
--font-weight-medium: 500;
|
| 98 |
+
--font-weight-semibold: 550;
|
| 99 |
+
--font-weight-bold: 600;
|
| 100 |
+
--line-height-tight: 1.2;
|
| 101 |
+
--line-height-normal: 1.5;
|
| 102 |
+
--letter-spacing-tight: -0.01em;
|
| 103 |
+
|
| 104 |
+
/* Spacing */
|
| 105 |
+
--space-0: 0;
|
| 106 |
+
--space-1: 1px;
|
| 107 |
+
--space-2: 2px;
|
| 108 |
+
--space-4: 4px;
|
| 109 |
+
--space-6: 6px;
|
| 110 |
+
--space-8: 8px;
|
| 111 |
+
--space-10: 10px;
|
| 112 |
+
--space-12: 12px;
|
| 113 |
+
--space-16: 16px;
|
| 114 |
+
--space-20: 20px;
|
| 115 |
+
--space-24: 24px;
|
| 116 |
+
--space-32: 32px;
|
| 117 |
+
|
| 118 |
+
/* Border Radius */
|
| 119 |
+
--radius-sm: 6px;
|
| 120 |
+
--radius-base: 8px;
|
| 121 |
+
--radius-md: 10px;
|
| 122 |
+
--radius-lg: 12px;
|
| 123 |
+
--radius-full: 9999px;
|
| 124 |
+
|
| 125 |
+
/* Shadows */
|
| 126 |
+
--shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.02);
|
| 127 |
+
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.02);
|
| 128 |
+
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.04),
|
| 129 |
+
0 2px 4px -1px rgba(0, 0, 0, 0.02);
|
| 130 |
+
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.04),
|
| 131 |
+
0 4px 6px -2px rgba(0, 0, 0, 0.02);
|
| 132 |
+
--shadow-inset-sm: inset 0 1px 0 rgba(255, 255, 255, 0.15),
|
| 133 |
+
inset 0 -1px 0 rgba(0, 0, 0, 0.03);
|
| 134 |
+
|
| 135 |
+
/* Animation */
|
| 136 |
+
--duration-fast: 150ms;
|
| 137 |
+
--duration-normal: 250ms;
|
| 138 |
+
--ease-standard: cubic-bezier(0.16, 1, 0.3, 1);
|
| 139 |
+
|
| 140 |
+
/* Layout */
|
| 141 |
+
--container-sm: 640px;
|
| 142 |
+
--container-md: 768px;
|
| 143 |
+
--container-lg: 1024px;
|
| 144 |
+
--container-xl: 1280px;
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
/* Dark mode colors */
|
| 148 |
+
@media (prefers-color-scheme: dark) {
|
| 149 |
+
:root {
|
| 150 |
+
/* RGB versions for opacity control (Dark Mode) */
|
| 151 |
+
--color-gray-400-rgb: 119, 124, 124;
|
| 152 |
+
--color-teal-300-rgb: 50, 184, 198;
|
| 153 |
+
--color-gray-300-rgb: 167, 169, 169;
|
| 154 |
+
--color-gray-200-rgb: 245, 245, 245;
|
| 155 |
+
|
| 156 |
+
/* Background color tokens (Dark Mode) */
|
| 157 |
+
--color-bg-1: rgba(29, 78, 216, 0.15); /* Dark blue */
|
| 158 |
+
--color-bg-2: rgba(180, 83, 9, 0.15); /* Dark yellow */
|
| 159 |
+
--color-bg-3: rgba(21, 128, 61, 0.15); /* Dark green */
|
| 160 |
+
--color-bg-4: rgba(185, 28, 28, 0.15); /* Dark red */
|
| 161 |
+
--color-bg-5: rgba(107, 33, 168, 0.15); /* Dark purple */
|
| 162 |
+
--color-bg-6: rgba(194, 65, 12, 0.15); /* Dark orange */
|
| 163 |
+
--color-bg-7: rgba(190, 24, 93, 0.15); /* Dark pink */
|
| 164 |
+
--color-bg-8: rgba(8, 145, 178, 0.15); /* Dark cyan */
|
| 165 |
+
|
| 166 |
+
/* Semantic Color Tokens (Dark Mode) */
|
| 167 |
+
--color-background: var(--color-charcoal-700);
|
| 168 |
+
--color-surface: var(--color-charcoal-800);
|
| 169 |
+
--color-text: var(--color-gray-200);
|
| 170 |
+
--color-text-secondary: rgba(var(--color-gray-300-rgb), 0.7);
|
| 171 |
+
--color-primary: var(--color-teal-300);
|
| 172 |
+
--color-primary-hover: var(--color-teal-400);
|
| 173 |
+
--color-primary-active: var(--color-teal-800);
|
| 174 |
+
--color-secondary: rgba(var(--color-gray-400-rgb), 0.15);
|
| 175 |
+
--color-secondary-hover: rgba(var(--color-gray-400-rgb), 0.25);
|
| 176 |
+
--color-secondary-active: rgba(var(--color-gray-400-rgb), 0.3);
|
| 177 |
+
--color-border: rgba(var(--color-gray-400-rgb), 0.3);
|
| 178 |
+
--color-error: var(--color-red-400);
|
| 179 |
+
--color-success: var(--color-teal-300);
|
| 180 |
+
--color-warning: var(--color-orange-400);
|
| 181 |
+
--color-info: var(--color-gray-300);
|
| 182 |
+
--color-focus-ring: rgba(var(--color-teal-300-rgb), 0.4);
|
| 183 |
+
--color-btn-primary-text: var(--color-slate-900);
|
| 184 |
+
--color-card-border: rgba(var(--color-gray-400-rgb), 0.2);
|
| 185 |
+
--color-card-border-inner: rgba(var(--color-gray-400-rgb), 0.15);
|
| 186 |
+
--shadow-inset-sm: inset 0 1px 0 rgba(255, 255, 255, 0.1),
|
| 187 |
+
inset 0 -1px 0 rgba(0, 0, 0, 0.15);
|
| 188 |
+
--button-border-secondary: rgba(var(--color-gray-400-rgb), 0.2);
|
| 189 |
+
--color-border-secondary: rgba(var(--color-gray-400-rgb), 0.2);
|
| 190 |
+
--color-select-caret: rgba(var(--color-gray-200-rgb), 0.8);
|
| 191 |
+
|
| 192 |
+
/* Common style patterns - updated for dark mode */
|
| 193 |
+
--focus-ring: 0 0 0 3px var(--color-focus-ring);
|
| 194 |
+
--focus-outline: 2px solid var(--color-primary);
|
| 195 |
+
--status-bg-opacity: 0.15;
|
| 196 |
+
--status-border-opacity: 0.25;
|
| 197 |
+
--select-caret-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23134252' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
|
| 198 |
+
--select-caret-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23f5f5f5' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
|
| 199 |
+
|
| 200 |
+
/* RGB versions for dark mode */
|
| 201 |
+
--color-success-rgb: var(--color-teal-300-rgb);
|
| 202 |
+
--color-error-rgb: var(--color-red-400-rgb);
|
| 203 |
+
--color-warning-rgb: var(--color-orange-400-rgb);
|
| 204 |
+
--color-info-rgb: var(--color-gray-300-rgb);
|
| 205 |
+
}
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
/* Data attribute for manual theme switching */
|
| 209 |
+
[data-color-scheme="dark"] {
|
| 210 |
+
/* RGB versions for opacity control (dark mode) */
|
| 211 |
+
--color-gray-400-rgb: 119, 124, 124;
|
| 212 |
+
--color-teal-300-rgb: 50, 184, 198;
|
| 213 |
+
--color-gray-300-rgb: 167, 169, 169;
|
| 214 |
+
--color-gray-200-rgb: 245, 245, 245;
|
| 215 |
+
|
| 216 |
+
/* Colorful background palette - Dark Mode */
|
| 217 |
+
--color-bg-1: rgba(29, 78, 216, 0.15); /* Dark blue */
|
| 218 |
+
--color-bg-2: rgba(180, 83, 9, 0.15); /* Dark yellow */
|
| 219 |
+
--color-bg-3: rgba(21, 128, 61, 0.15); /* Dark green */
|
| 220 |
+
--color-bg-4: rgba(185, 28, 28, 0.15); /* Dark red */
|
| 221 |
+
--color-bg-5: rgba(107, 33, 168, 0.15); /* Dark purple */
|
| 222 |
+
--color-bg-6: rgba(194, 65, 12, 0.15); /* Dark orange */
|
| 223 |
+
--color-bg-7: rgba(190, 24, 93, 0.15); /* Dark pink */
|
| 224 |
+
--color-bg-8: rgba(8, 145, 178, 0.15); /* Dark cyan */
|
| 225 |
+
|
| 226 |
+
/* Semantic Color Tokens (Dark Mode) */
|
| 227 |
+
--color-background: var(--color-charcoal-700);
|
| 228 |
+
--color-surface: var(--color-charcoal-800);
|
| 229 |
+
--color-text: var(--color-gray-200);
|
| 230 |
+
--color-text-secondary: rgba(var(--color-gray-300-rgb), 0.7);
|
| 231 |
+
--color-primary: var(--color-teal-300);
|
| 232 |
+
--color-primary-hover: var(--color-teal-400);
|
| 233 |
+
--color-primary-active: var(--color-teal-800);
|
| 234 |
+
--color-secondary: rgba(var(--color-gray-400-rgb), 0.15);
|
| 235 |
+
--color-secondary-hover: rgba(var(--color-gray-400-rgb), 0.25);
|
| 236 |
+
--color-secondary-active: rgba(var(--color-gray-400-rgb), 0.3);
|
| 237 |
+
--color-border: rgba(var(--color-gray-400-rgb), 0.3);
|
| 238 |
+
--color-error: var(--color-red-400);
|
| 239 |
+
--color-success: var(--color-teal-300);
|
| 240 |
+
--color-warning: var(--color-orange-400);
|
| 241 |
+
--color-info: var(--color-gray-300);
|
| 242 |
+
--color-focus-ring: rgba(var(--color-teal-300-rgb), 0.4);
|
| 243 |
+
--color-btn-primary-text: var(--color-slate-900);
|
| 244 |
+
--color-card-border: rgba(var(--color-gray-400-rgb), 0.15);
|
| 245 |
+
--color-card-border-inner: rgba(var(--color-gray-400-rgb), 0.15);
|
| 246 |
+
--shadow-inset-sm: inset 0 1px 0 rgba(255, 255, 255, 0.1),
|
| 247 |
+
inset 0 -1px 0 rgba(0, 0, 0, 0.15);
|
| 248 |
+
--color-border-secondary: rgba(var(--color-gray-400-rgb), 0.2);
|
| 249 |
+
--color-select-caret: rgba(var(--color-gray-200-rgb), 0.8);
|
| 250 |
+
|
| 251 |
+
/* Common style patterns - updated for dark mode */
|
| 252 |
+
--focus-ring: 0 0 0 3px var(--color-focus-ring);
|
| 253 |
+
--focus-outline: 2px solid var(--color-primary);
|
| 254 |
+
--status-bg-opacity: 0.15;
|
| 255 |
+
--status-border-opacity: 0.25;
|
| 256 |
+
--select-caret-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23134252' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
|
| 257 |
+
--select-caret-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23f5f5f5' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
|
| 258 |
+
|
| 259 |
+
/* RGB versions for dark mode */
|
| 260 |
+
--color-success-rgb: var(--color-teal-300-rgb);
|
| 261 |
+
--color-error-rgb: var(--color-red-400-rgb);
|
| 262 |
+
--color-warning-rgb: var(--color-orange-400-rgb);
|
| 263 |
+
--color-info-rgb: var(--color-gray-300-rgb);
|
| 264 |
+
}
|
| 265 |
+
|
| 266 |
+
[data-color-scheme="light"] {
|
| 267 |
+
/* RGB versions for opacity control (light mode) */
|
| 268 |
+
--color-brown-600-rgb: 94, 82, 64;
|
| 269 |
+
--color-teal-500-rgb: 33, 128, 141;
|
| 270 |
+
--color-slate-900-rgb: 19, 52, 59;
|
| 271 |
+
|
| 272 |
+
/* Semantic Color Tokens (Light Mode) */
|
| 273 |
+
--color-background: var(--color-cream-50);
|
| 274 |
+
--color-surface: var(--color-cream-100);
|
| 275 |
+
--color-text: var(--color-slate-900);
|
| 276 |
+
--color-text-secondary: var(--color-slate-500);
|
| 277 |
+
--color-primary: var(--color-teal-500);
|
| 278 |
+
--color-primary-hover: var(--color-teal-600);
|
| 279 |
+
--color-primary-active: var(--color-teal-700);
|
| 280 |
+
--color-secondary: rgba(var(--color-brown-600-rgb), 0.12);
|
| 281 |
+
--color-secondary-hover: rgba(var(--color-brown-600-rgb), 0.2);
|
| 282 |
+
--color-secondary-active: rgba(var(--color-brown-600-rgb), 0.25);
|
| 283 |
+
--color-border: rgba(var(--color-brown-600-rgb), 0.2);
|
| 284 |
+
--color-btn-primary-text: var(--color-cream-50);
|
| 285 |
+
--color-card-border: rgba(var(--color-brown-600-rgb), 0.12);
|
| 286 |
+
--color-card-border-inner: rgba(var(--color-brown-600-rgb), 0.12);
|
| 287 |
+
--color-error: var(--color-red-500);
|
| 288 |
+
--color-success: var(--color-teal-500);
|
| 289 |
+
--color-warning: var(--color-orange-500);
|
| 290 |
+
--color-info: var(--color-slate-500);
|
| 291 |
+
--color-focus-ring: rgba(var(--color-teal-500-rgb), 0.4);
|
| 292 |
+
|
| 293 |
+
/* RGB versions for light mode */
|
| 294 |
+
--color-success-rgb: var(--color-teal-500-rgb);
|
| 295 |
+
--color-error-rgb: var(--color-red-500-rgb);
|
| 296 |
+
--color-warning-rgb: var(--color-orange-500-rgb);
|
| 297 |
+
--color-info-rgb: var(--color-slate-500-rgb);
|
| 298 |
+
}
|
| 299 |
+
|
| 300 |
+
/* Base styles */
|
| 301 |
+
html {
|
| 302 |
+
font-size: var(--font-size-base);
|
| 303 |
+
font-family: var(--font-family-base);
|
| 304 |
+
line-height: var(--line-height-normal);
|
| 305 |
+
color: var(--color-text);
|
| 306 |
+
background-color: var(--color-background);
|
| 307 |
+
-webkit-font-smoothing: antialiased;
|
| 308 |
+
box-sizing: border-box;
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
body {
|
| 312 |
+
margin: 0;
|
| 313 |
+
padding: 0;
|
| 314 |
+
}
|
| 315 |
+
|
| 316 |
+
*,
|
| 317 |
+
*::before,
|
| 318 |
+
*::after {
|
| 319 |
+
box-sizing: inherit;
|
| 320 |
+
}
|
| 321 |
+
|
| 322 |
+
/* Typography */
|
| 323 |
+
h1,
|
| 324 |
+
h2,
|
| 325 |
+
h3,
|
| 326 |
+
h4,
|
| 327 |
+
h5,
|
| 328 |
+
h6 {
|
| 329 |
+
margin: 0;
|
| 330 |
+
font-weight: var(--font-weight-semibold);
|
| 331 |
+
line-height: var(--line-height-tight);
|
| 332 |
+
color: var(--color-text);
|
| 333 |
+
letter-spacing: var(--letter-spacing-tight);
|
| 334 |
+
}
|
| 335 |
+
|
| 336 |
+
h1 {
|
| 337 |
+
font-size: var(--font-size-4xl);
|
| 338 |
+
}
|
| 339 |
+
h2 {
|
| 340 |
+
font-size: var(--font-size-3xl);
|
| 341 |
+
}
|
| 342 |
+
h3 {
|
| 343 |
+
font-size: var(--font-size-2xl);
|
| 344 |
+
}
|
| 345 |
+
h4 {
|
| 346 |
+
font-size: var(--font-size-xl);
|
| 347 |
+
}
|
| 348 |
+
h5 {
|
| 349 |
+
font-size: var(--font-size-lg);
|
| 350 |
+
}
|
| 351 |
+
h6 {
|
| 352 |
+
font-size: var(--font-size-md);
|
| 353 |
+
}
|
| 354 |
+
|
| 355 |
+
p {
|
| 356 |
+
margin: 0 0 var(--space-16) 0;
|
| 357 |
+
}
|
| 358 |
+
|
| 359 |
+
a {
|
| 360 |
+
color: var(--color-primary);
|
| 361 |
+
text-decoration: none;
|
| 362 |
+
transition: color var(--duration-fast) var(--ease-standard);
|
| 363 |
+
}
|
| 364 |
+
|
| 365 |
+
a:hover {
|
| 366 |
+
color: var(--color-primary-hover);
|
| 367 |
+
}
|
| 368 |
+
|
| 369 |
+
code,
|
| 370 |
+
pre {
|
| 371 |
+
font-family: var(--font-family-mono);
|
| 372 |
+
font-size: calc(var(--font-size-base) * 0.95);
|
| 373 |
+
background-color: var(--color-secondary);
|
| 374 |
+
border-radius: var(--radius-sm);
|
| 375 |
+
}
|
| 376 |
+
|
| 377 |
+
code {
|
| 378 |
+
padding: var(--space-1) var(--space-4);
|
| 379 |
+
}
|
| 380 |
+
|
| 381 |
+
pre {
|
| 382 |
+
padding: var(--space-16);
|
| 383 |
+
margin: var(--space-16) 0;
|
| 384 |
+
overflow: auto;
|
| 385 |
+
border: 1px solid var(--color-border);
|
| 386 |
+
}
|
| 387 |
+
|
| 388 |
+
pre code {
|
| 389 |
+
background: none;
|
| 390 |
+
padding: 0;
|
| 391 |
+
}
|
| 392 |
+
|
| 393 |
+
/* Buttons */
|
| 394 |
+
.btn {
|
| 395 |
+
display: inline-flex;
|
| 396 |
+
align-items: center;
|
| 397 |
+
justify-content: center;
|
| 398 |
+
padding: var(--space-8) var(--space-16);
|
| 399 |
+
border-radius: var(--radius-base);
|
| 400 |
+
font-size: var(--font-size-base);
|
| 401 |
+
font-weight: 500;
|
| 402 |
+
line-height: 1.5;
|
| 403 |
+
cursor: pointer;
|
| 404 |
+
transition: all var(--duration-normal) var(--ease-standard);
|
| 405 |
+
border: none;
|
| 406 |
+
text-decoration: none;
|
| 407 |
+
position: relative;
|
| 408 |
+
}
|
| 409 |
+
|
| 410 |
+
.btn:focus-visible {
|
| 411 |
+
outline: none;
|
| 412 |
+
box-shadow: var(--focus-ring);
|
| 413 |
+
}
|
| 414 |
+
|
| 415 |
+
.btn--primary {
|
| 416 |
+
background: var(--color-primary);
|
| 417 |
+
color: var(--color-btn-primary-text);
|
| 418 |
+
}
|
| 419 |
+
|
| 420 |
+
.btn--primary:hover {
|
| 421 |
+
background: var(--color-primary-hover);
|
| 422 |
+
}
|
| 423 |
+
|
| 424 |
+
.btn--primary:active {
|
| 425 |
+
background: var(--color-primary-active);
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
.btn--secondary {
|
| 429 |
+
background: var(--color-secondary);
|
| 430 |
+
color: var(--color-text);
|
| 431 |
+
}
|
| 432 |
+
|
| 433 |
+
.btn--secondary:hover {
|
| 434 |
+
background: var(--color-secondary-hover);
|
| 435 |
+
}
|
| 436 |
+
|
| 437 |
+
.btn--secondary:active {
|
| 438 |
+
background: var(--color-secondary-active);
|
| 439 |
+
}
|
| 440 |
+
|
| 441 |
+
.btn--outline {
|
| 442 |
+
background: transparent;
|
| 443 |
+
border: 1px solid var(--color-border);
|
| 444 |
+
color: var(--color-text);
|
| 445 |
+
}
|
| 446 |
+
|
| 447 |
+
.btn--outline:hover {
|
| 448 |
+
background: var(--color-secondary);
|
| 449 |
+
}
|
| 450 |
+
|
| 451 |
+
.btn--sm {
|
| 452 |
+
padding: var(--space-4) var(--space-12);
|
| 453 |
+
font-size: var(--font-size-sm);
|
| 454 |
+
border-radius: var(--radius-sm);
|
| 455 |
+
}
|
| 456 |
+
|
| 457 |
+
.btn--lg {
|
| 458 |
+
padding: var(--space-10) var(--space-20);
|
| 459 |
+
font-size: var(--font-size-lg);
|
| 460 |
+
border-radius: var(--radius-md);
|
| 461 |
+
}
|
| 462 |
+
|
| 463 |
+
.btn--full-width {
|
| 464 |
+
width: 100%;
|
| 465 |
+
}
|
| 466 |
+
|
| 467 |
+
.btn:disabled {
|
| 468 |
+
opacity: 0.5;
|
| 469 |
+
cursor: not-allowed;
|
| 470 |
+
}
|
| 471 |
+
|
| 472 |
+
/* Form elements */
|
| 473 |
+
.form-control {
|
| 474 |
+
display: block;
|
| 475 |
+
width: 100%;
|
| 476 |
+
padding: var(--space-8) var(--space-12);
|
| 477 |
+
font-size: var(--font-size-md);
|
| 478 |
+
line-height: 1.5;
|
| 479 |
+
color: var(--color-text);
|
| 480 |
+
background-color: var(--color-surface);
|
| 481 |
+
border: 1px solid var(--color-border);
|
| 482 |
+
border-radius: var(--radius-base);
|
| 483 |
+
transition: border-color var(--duration-fast) var(--ease-standard),
|
| 484 |
+
box-shadow var(--duration-fast) var(--ease-standard);
|
| 485 |
+
}
|
| 486 |
+
|
| 487 |
+
textarea.form-control {
|
| 488 |
+
font-family: var(--font-family-base);
|
| 489 |
+
font-size: var(--font-size-base);
|
| 490 |
+
}
|
| 491 |
+
|
| 492 |
+
select.form-control {
|
| 493 |
+
padding: var(--space-8) var(--space-12);
|
| 494 |
+
-webkit-appearance: none;
|
| 495 |
+
-moz-appearance: none;
|
| 496 |
+
appearance: none;
|
| 497 |
+
background-image: var(--select-caret-light);
|
| 498 |
+
background-repeat: no-repeat;
|
| 499 |
+
background-position: right var(--space-12) center;
|
| 500 |
+
background-size: 16px;
|
| 501 |
+
padding-right: var(--space-32);
|
| 502 |
+
}
|
| 503 |
+
|
| 504 |
+
/* Add a dark mode specific caret */
|
| 505 |
+
@media (prefers-color-scheme: dark) {
|
| 506 |
+
select.form-control {
|
| 507 |
+
background-image: var(--select-caret-dark);
|
| 508 |
+
}
|
| 509 |
+
}
|
| 510 |
+
|
| 511 |
+
/* Also handle data-color-scheme */
|
| 512 |
+
[data-color-scheme="dark"] select.form-control {
|
| 513 |
+
background-image: var(--select-caret-dark);
|
| 514 |
+
}
|
| 515 |
+
|
| 516 |
+
[data-color-scheme="light"] select.form-control {
|
| 517 |
+
background-image: var(--select-caret-light);
|
| 518 |
+
}
|
| 519 |
+
|
| 520 |
+
.form-control:focus {
|
| 521 |
+
border-color: var(--color-primary);
|
| 522 |
+
outline: var(--focus-outline);
|
| 523 |
+
}
|
| 524 |
+
|
| 525 |
+
.form-label {
|
| 526 |
+
display: block;
|
| 527 |
+
margin-bottom: var(--space-8);
|
| 528 |
+
font-weight: var(--font-weight-medium);
|
| 529 |
+
font-size: var(--font-size-sm);
|
| 530 |
+
}
|
| 531 |
+
|
| 532 |
+
.form-group {
|
| 533 |
+
margin-bottom: var(--space-16);
|
| 534 |
+
}
|
| 535 |
+
|
| 536 |
+
/* Card component */
|
| 537 |
+
.card {
|
| 538 |
+
background-color: var(--color-surface);
|
| 539 |
+
border-radius: var(--radius-lg);
|
| 540 |
+
border: 1px solid var(--color-card-border);
|
| 541 |
+
box-shadow: var(--shadow-sm);
|
| 542 |
+
overflow: hidden;
|
| 543 |
+
transition: box-shadow var(--duration-normal) var(--ease-standard);
|
| 544 |
+
}
|
| 545 |
+
|
| 546 |
+
.card:hover {
|
| 547 |
+
box-shadow: var(--shadow-md);
|
| 548 |
+
}
|
| 549 |
+
|
| 550 |
+
.card__body {
|
| 551 |
+
padding: var(--space-16);
|
| 552 |
+
}
|
| 553 |
+
|
| 554 |
+
.card__header,
|
| 555 |
+
.card__footer {
|
| 556 |
+
padding: var(--space-16);
|
| 557 |
+
border-bottom: 1px solid var(--color-card-border-inner);
|
| 558 |
+
}
|
| 559 |
+
|
| 560 |
+
/* Status indicators - simplified with CSS variables */
|
| 561 |
+
.status {
|
| 562 |
+
display: inline-flex;
|
| 563 |
+
align-items: center;
|
| 564 |
+
padding: var(--space-6) var(--space-12);
|
| 565 |
+
border-radius: var(--radius-full);
|
| 566 |
+
font-weight: var(--font-weight-medium);
|
| 567 |
+
font-size: var(--font-size-sm);
|
| 568 |
+
}
|
| 569 |
+
|
| 570 |
+
.status--success {
|
| 571 |
+
background-color: rgba(
|
| 572 |
+
var(--color-success-rgb, 33, 128, 141),
|
| 573 |
+
var(--status-bg-opacity)
|
| 574 |
+
);
|
| 575 |
+
color: var(--color-success);
|
| 576 |
+
border: 1px solid
|
| 577 |
+
rgba(var(--color-success-rgb, 33, 128, 141), var(--status-border-opacity));
|
| 578 |
+
}
|
| 579 |
+
|
| 580 |
+
.status--error {
|
| 581 |
+
background-color: rgba(
|
| 582 |
+
var(--color-error-rgb, 192, 21, 47),
|
| 583 |
+
var(--status-bg-opacity)
|
| 584 |
+
);
|
| 585 |
+
color: var(--color-error);
|
| 586 |
+
border: 1px solid
|
| 587 |
+
rgba(var(--color-error-rgb, 192, 21, 47), var(--status-border-opacity));
|
| 588 |
+
}
|
| 589 |
+
|
| 590 |
+
.status--warning {
|
| 591 |
+
background-color: rgba(
|
| 592 |
+
var(--color-warning-rgb, 168, 75, 47),
|
| 593 |
+
var(--status-bg-opacity)
|
| 594 |
+
);
|
| 595 |
+
color: var(--color-warning);
|
| 596 |
+
border: 1px solid
|
| 597 |
+
rgba(var(--color-warning-rgb, 168, 75, 47), var(--status-border-opacity));
|
| 598 |
+
}
|
| 599 |
+
|
| 600 |
+
.status--info {
|
| 601 |
+
background-color: rgba(
|
| 602 |
+
var(--color-info-rgb, 98, 108, 113),
|
| 603 |
+
var(--status-bg-opacity)
|
| 604 |
+
);
|
| 605 |
+
color: var(--color-info);
|
| 606 |
+
border: 1px solid
|
| 607 |
+
rgba(var(--color-info-rgb, 98, 108, 113), var(--status-border-opacity));
|
| 608 |
+
}
|
| 609 |
+
|
| 610 |
+
/* Container layout */
|
| 611 |
+
.container {
|
| 612 |
+
width: 100%;
|
| 613 |
+
margin-right: auto;
|
| 614 |
+
margin-left: auto;
|
| 615 |
+
padding-right: var(--space-16);
|
| 616 |
+
padding-left: var(--space-16);
|
| 617 |
+
}
|
| 618 |
+
|
| 619 |
+
@media (min-width: 640px) {
|
| 620 |
+
.container {
|
| 621 |
+
max-width: var(--container-sm);
|
| 622 |
+
}
|
| 623 |
+
}
|
| 624 |
+
@media (min-width: 768px) {
|
| 625 |
+
.container {
|
| 626 |
+
max-width: var(--container-md);
|
| 627 |
+
}
|
| 628 |
+
}
|
| 629 |
+
@media (min-width: 1024px) {
|
| 630 |
+
.container {
|
| 631 |
+
max-width: var(--container-lg);
|
| 632 |
+
}
|
| 633 |
+
}
|
| 634 |
+
@media (min-width: 1280px) {
|
| 635 |
+
.container {
|
| 636 |
+
max-width: var(--container-xl);
|
| 637 |
+
}
|
| 638 |
+
}
|
| 639 |
+
|
| 640 |
+
/* Utility classes */
|
| 641 |
+
.flex {
|
| 642 |
+
display: flex;
|
| 643 |
+
}
|
| 644 |
+
.flex-col {
|
| 645 |
+
flex-direction: column;
|
| 646 |
+
}
|
| 647 |
+
.items-center {
|
| 648 |
+
align-items: center;
|
| 649 |
+
}
|
| 650 |
+
.justify-center {
|
| 651 |
+
justify-content: center;
|
| 652 |
+
}
|
| 653 |
+
.justify-between {
|
| 654 |
+
justify-content: space-between;
|
| 655 |
+
}
|
| 656 |
+
.gap-4 {
|
| 657 |
+
gap: var(--space-4);
|
| 658 |
+
}
|
| 659 |
+
.gap-8 {
|
| 660 |
+
gap: var(--space-8);
|
| 661 |
+
}
|
| 662 |
+
.gap-16 {
|
| 663 |
+
gap: var(--space-16);
|
| 664 |
+
}
|
| 665 |
+
|
| 666 |
+
.m-0 {
|
| 667 |
+
margin: 0;
|
| 668 |
+
}
|
| 669 |
+
.mt-8 {
|
| 670 |
+
margin-top: var(--space-8);
|
| 671 |
+
}
|
| 672 |
+
.mb-8 {
|
| 673 |
+
margin-bottom: var(--space-8);
|
| 674 |
+
}
|
| 675 |
+
.mx-8 {
|
| 676 |
+
margin-left: var(--space-8);
|
| 677 |
+
margin-right: var(--space-8);
|
| 678 |
+
}
|
| 679 |
+
.my-8 {
|
| 680 |
+
margin-top: var(--space-8);
|
| 681 |
+
margin-bottom: var(--space-8);
|
| 682 |
+
}
|
| 683 |
+
|
| 684 |
+
.p-0 {
|
| 685 |
+
padding: 0;
|
| 686 |
+
}
|
| 687 |
+
.py-8 {
|
| 688 |
+
padding-top: var(--space-8);
|
| 689 |
+
padding-bottom: var(--space-8);
|
| 690 |
+
}
|
| 691 |
+
.px-8 {
|
| 692 |
+
padding-left: var(--space-8);
|
| 693 |
+
padding-right: var(--space-8);
|
| 694 |
+
}
|
| 695 |
+
.py-16 {
|
| 696 |
+
padding-top: var(--space-16);
|
| 697 |
+
padding-bottom: var(--space-16);
|
| 698 |
+
}
|
| 699 |
+
.px-16 {
|
| 700 |
+
padding-left: var(--space-16);
|
| 701 |
+
padding-right: var(--space-16);
|
| 702 |
+
}
|
| 703 |
+
|
| 704 |
+
.block {
|
| 705 |
+
display: block;
|
| 706 |
+
}
|
| 707 |
+
.hidden {
|
| 708 |
+
display: none;
|
| 709 |
+
}
|
| 710 |
+
|
| 711 |
+
/* Accessibility */
|
| 712 |
+
.sr-only {
|
| 713 |
+
position: absolute;
|
| 714 |
+
width: 1px;
|
| 715 |
+
height: 1px;
|
| 716 |
+
padding: 0;
|
| 717 |
+
margin: -1px;
|
| 718 |
+
overflow: hidden;
|
| 719 |
+
clip: rect(0, 0, 0, 0);
|
| 720 |
+
white-space: nowrap;
|
| 721 |
+
border-width: 0;
|
| 722 |
+
}
|
| 723 |
+
|
| 724 |
+
:focus-visible {
|
| 725 |
+
outline: var(--focus-outline);
|
| 726 |
+
outline-offset: 2px;
|
| 727 |
+
}
|
| 728 |
+
|
| 729 |
+
/* Dark mode specifics */
|
| 730 |
+
[data-color-scheme="dark"] .btn--outline {
|
| 731 |
+
border: 1px solid var(--color-border-secondary);
|
| 732 |
+
}
|
| 733 |
+
|
| 734 |
+
@font-face {
|
| 735 |
+
font-family: 'FKGroteskNeue';
|
| 736 |
+
src: url('https://r2cdn.perplexity.ai/fonts/FKGroteskNeue.woff2')
|
| 737 |
+
format('woff2');
|
| 738 |
+
}
|
| 739 |
+
|
| 740 |
+
/* END PERPLEXITY DESIGN SYSTEM */
|
| 741 |
+
/* Reset and Base Styles */
|
| 742 |
+
* {
|
| 743 |
+
margin: 0;
|
| 744 |
+
padding: 0;
|
| 745 |
+
box-sizing: border-box;
|
| 746 |
+
}
|
| 747 |
+
|
| 748 |
+
html {
|
| 749 |
+
scroll-behavior: smooth;
|
| 750 |
+
}
|
| 751 |
+
|
| 752 |
+
body {
|
| 753 |
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
| 754 |
+
background-color: #1a1a2e;
|
| 755 |
+
color: #e1e1e1;
|
| 756 |
+
line-height: 1.6;
|
| 757 |
+
overflow-x: hidden;
|
| 758 |
+
}
|
| 759 |
+
|
| 760 |
+
/* Top Navigation */
|
| 761 |
+
.top-nav {
|
| 762 |
+
position: sticky;
|
| 763 |
+
top: 0;
|
| 764 |
+
background: linear-gradient(135deg, #16213e 0%, #0f3460 100%);
|
| 765 |
+
padding: 1rem 0;
|
| 766 |
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
| 767 |
+
z-index: 1000;
|
| 768 |
+
border-bottom: 2px solid #4a90e2;
|
| 769 |
+
}
|
| 770 |
+
|
| 771 |
+
.nav-container {
|
| 772 |
+
max-width: 1400px;
|
| 773 |
+
margin: 0 auto;
|
| 774 |
+
padding: 0 2rem;
|
| 775 |
+
display: flex;
|
| 776 |
+
justify-content: space-between;
|
| 777 |
+
align-items: center;
|
| 778 |
+
}
|
| 779 |
+
|
| 780 |
+
.course-title {
|
| 781 |
+
font-size: 1.8rem;
|
| 782 |
+
color: #64ffda;
|
| 783 |
+
font-weight: 700;
|
| 784 |
+
text-shadow: 0 0 20px rgba(100, 255, 218, 0.3);
|
| 785 |
+
}
|
| 786 |
+
|
| 787 |
+
.mobile-menu-btn {
|
| 788 |
+
display: none;
|
| 789 |
+
flex-direction: column;
|
| 790 |
+
background: none;
|
| 791 |
+
border: none;
|
| 792 |
+
cursor: pointer;
|
| 793 |
+
padding: 0.5rem;
|
| 794 |
+
}
|
| 795 |
+
|
| 796 |
+
.mobile-menu-btn span {
|
| 797 |
+
width: 25px;
|
| 798 |
+
height: 3px;
|
| 799 |
+
background: #64ffda;
|
| 800 |
+
margin: 3px 0;
|
| 801 |
+
border-radius: 3px;
|
| 802 |
+
transition: all 0.3s ease;
|
| 803 |
+
}
|
| 804 |
+
|
| 805 |
+
/* Main Container */
|
| 806 |
+
.main-container {
|
| 807 |
+
display: flex;
|
| 808 |
+
max-width: 1400px;
|
| 809 |
+
margin: 0 auto;
|
| 810 |
+
min-height: calc(100vh - 80px);
|
| 811 |
+
}
|
| 812 |
+
|
| 813 |
+
/* Sidebar */
|
| 814 |
+
.sidebar {
|
| 815 |
+
width: 280px;
|
| 816 |
+
background: #16213e;
|
| 817 |
+
padding: 2rem 1rem;
|
| 818 |
+
position: sticky;
|
| 819 |
+
top: 80px;
|
| 820 |
+
height: calc(100vh - 80px);
|
| 821 |
+
overflow-y: auto;
|
| 822 |
+
border-right: 2px solid #0f3460;
|
| 823 |
+
transition: transform 0.3s ease;
|
| 824 |
+
}
|
| 825 |
+
|
| 826 |
+
.sidebar-content h3 {
|
| 827 |
+
color: #64ffda;
|
| 828 |
+
margin-bottom: 1.5rem;
|
| 829 |
+
font-size: 1.3rem;
|
| 830 |
+
text-align: center;
|
| 831 |
+
}
|
| 832 |
+
|
| 833 |
+
.module {
|
| 834 |
+
margin-bottom: 2rem;
|
| 835 |
+
}
|
| 836 |
+
|
| 837 |
+
.module-title {
|
| 838 |
+
color: #4a90e2;
|
| 839 |
+
font-size: 0.9rem;
|
| 840 |
+
text-transform: uppercase;
|
| 841 |
+
letter-spacing: 1px;
|
| 842 |
+
margin-bottom: 0.8rem;
|
| 843 |
+
padding: 0.5rem;
|
| 844 |
+
background: rgba(74, 144, 226, 0.1);
|
| 845 |
+
border-radius: 5px;
|
| 846 |
+
border-left: 3px solid #4a90e2;
|
| 847 |
+
}
|
| 848 |
+
|
| 849 |
+
.topic-list {
|
| 850 |
+
list-style: none;
|
| 851 |
+
}
|
| 852 |
+
|
| 853 |
+
.topic-list li {
|
| 854 |
+
margin-bottom: 0.5rem;
|
| 855 |
+
}
|
| 856 |
+
|
| 857 |
+
.topic-link {
|
| 858 |
+
display: block;
|
| 859 |
+
padding: 0.6rem 0.8rem;
|
| 860 |
+
color: #a0a0a0;
|
| 861 |
+
text-decoration: none;
|
| 862 |
+
border-radius: 5px;
|
| 863 |
+
transition: all 0.3s ease;
|
| 864 |
+
font-size: 0.9rem;
|
| 865 |
+
border-left: 3px solid transparent;
|
| 866 |
+
}
|
| 867 |
+
|
| 868 |
+
.topic-link:hover {
|
| 869 |
+
background: rgba(100, 255, 218, 0.1);
|
| 870 |
+
color: #64ffda;
|
| 871 |
+
border-left-color: #64ffda;
|
| 872 |
+
transform: translateX(5px);
|
| 873 |
+
}
|
| 874 |
+
|
| 875 |
+
.topic-link.active {
|
| 876 |
+
background: rgba(100, 255, 218, 0.15);
|
| 877 |
+
color: #64ffda;
|
| 878 |
+
border-left-color: #64ffda;
|
| 879 |
+
font-weight: 600;
|
| 880 |
+
}
|
| 881 |
+
|
| 882 |
+
/* Scrollbar Styling */
|
| 883 |
+
.sidebar::-webkit-scrollbar {
|
| 884 |
+
width: 8px;
|
| 885 |
+
}
|
| 886 |
+
|
| 887 |
+
.sidebar::-webkit-scrollbar-track {
|
| 888 |
+
background: #0f3460;
|
| 889 |
+
}
|
| 890 |
+
|
| 891 |
+
.sidebar::-webkit-scrollbar-thumb {
|
| 892 |
+
background: #4a90e2;
|
| 893 |
+
border-radius: 4px;
|
| 894 |
+
}
|
| 895 |
+
|
| 896 |
+
.sidebar::-webkit-scrollbar-thumb:hover {
|
| 897 |
+
background: #64ffda;
|
| 898 |
+
}
|
| 899 |
+
|
| 900 |
+
/* Main Content */
|
| 901 |
+
.content {
|
| 902 |
+
flex: 1;
|
| 903 |
+
padding: 3rem;
|
| 904 |
+
background: #1a1a2e;
|
| 905 |
+
}
|
| 906 |
+
|
| 907 |
+
/* Topic Section */
|
| 908 |
+
.topic-section {
|
| 909 |
+
margin-bottom: 4rem;
|
| 910 |
+
opacity: 0;
|
| 911 |
+
transform: translateY(20px);
|
| 912 |
+
animation: fadeInUp 0.6s ease forwards;
|
| 913 |
+
}
|
| 914 |
+
|
| 915 |
+
@keyframes fadeInUp {
|
| 916 |
+
to {
|
| 917 |
+
opacity: 1;
|
| 918 |
+
transform: translateY(0);
|
| 919 |
+
}
|
| 920 |
+
}
|
| 921 |
+
|
| 922 |
+
.topic-header {
|
| 923 |
+
margin-bottom: 2rem;
|
| 924 |
+
padding-bottom: 1.5rem;
|
| 925 |
+
border-bottom: 3px solid #0f3460;
|
| 926 |
+
}
|
| 927 |
+
|
| 928 |
+
.topic-number {
|
| 929 |
+
display: inline-block;
|
| 930 |
+
background: linear-gradient(135deg, #4a90e2, #64ffda);
|
| 931 |
+
color: #1a1a2e;
|
| 932 |
+
padding: 0.3rem 1rem;
|
| 933 |
+
border-radius: 20px;
|
| 934 |
+
font-size: 0.85rem;
|
| 935 |
+
font-weight: 700;
|
| 936 |
+
margin-bottom: 0.8rem;
|
| 937 |
+
}
|
| 938 |
+
|
| 939 |
+
.topic-header h2 {
|
| 940 |
+
font-size: 2.5rem;
|
| 941 |
+
color: #64ffda;
|
| 942 |
+
margin-bottom: 0.5rem;
|
| 943 |
+
text-shadow: 0 0 20px rgba(100, 255, 218, 0.2);
|
| 944 |
+
}
|
| 945 |
+
|
| 946 |
+
.topic-subtitle {
|
| 947 |
+
color: #a0a0a0;
|
| 948 |
+
font-size: 1.1rem;
|
| 949 |
+
font-style: italic;
|
| 950 |
+
}
|
| 951 |
+
|
| 952 |
+
/* Content Cards */
|
| 953 |
+
.content-card {
|
| 954 |
+
background: #16213e;
|
| 955 |
+
padding: 2rem;
|
| 956 |
+
border-radius: 12px;
|
| 957 |
+
margin-bottom: 2rem;
|
| 958 |
+
border: 1px solid #0f3460;
|
| 959 |
+
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
|
| 960 |
+
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
| 961 |
+
}
|
| 962 |
+
|
| 963 |
+
.content-card:hover {
|
| 964 |
+
transform: translateY(-2px);
|
| 965 |
+
box-shadow: 0 6px 25px rgba(74, 144, 226, 0.2);
|
| 966 |
+
}
|
| 967 |
+
|
| 968 |
+
.content-card h3 {
|
| 969 |
+
color: #4a90e2;
|
| 970 |
+
margin-bottom: 1rem;
|
| 971 |
+
font-size: 1.5rem;
|
| 972 |
+
}
|
| 973 |
+
|
| 974 |
+
.content-card h4 {
|
| 975 |
+
margin-top: 1rem;
|
| 976 |
+
margin-bottom: 0.8rem;
|
| 977 |
+
font-size: 1.2rem;
|
| 978 |
+
}
|
| 979 |
+
|
| 980 |
+
.content-card p {
|
| 981 |
+
margin-bottom: 1rem;
|
| 982 |
+
color: #d0d0d0;
|
| 983 |
+
line-height: 1.8;
|
| 984 |
+
}
|
| 985 |
+
|
| 986 |
+
.content-card ul,
|
| 987 |
+
.content-card ol {
|
| 988 |
+
margin-left: 2rem;
|
| 989 |
+
margin-bottom: 1rem;
|
| 990 |
+
}
|
| 991 |
+
|
| 992 |
+
.content-card li {
|
| 993 |
+
margin-bottom: 0.5rem;
|
| 994 |
+
color: #d0d0d0;
|
| 995 |
+
}
|
| 996 |
+
|
| 997 |
+
/* Callout Boxes */
|
| 998 |
+
.callout-box {
|
| 999 |
+
padding: 1.5rem;
|
| 1000 |
+
border-radius: 10px;
|
| 1001 |
+
margin-bottom: 2rem;
|
| 1002 |
+
border-left: 4px solid;
|
| 1003 |
+
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
|
| 1004 |
+
}
|
| 1005 |
+
|
| 1006 |
+
.callout-header {
|
| 1007 |
+
font-weight: 700;
|
| 1008 |
+
font-size: 1rem;
|
| 1009 |
+
margin-bottom: 0.8rem;
|
| 1010 |
+
display: flex;
|
| 1011 |
+
align-items: center;
|
| 1012 |
+
gap: 0.5rem;
|
| 1013 |
+
}
|
| 1014 |
+
|
| 1015 |
+
.callout-box.insight {
|
| 1016 |
+
background: rgba(100, 255, 218, 0.1);
|
| 1017 |
+
border-left-color: #64ffda;
|
| 1018 |
+
}
|
| 1019 |
+
|
| 1020 |
+
.callout-box.insight .callout-header {
|
| 1021 |
+
color: #64ffda;
|
| 1022 |
+
}
|
| 1023 |
+
|
| 1024 |
+
.callout-box.warning {
|
| 1025 |
+
background: rgba(255, 107, 107, 0.1);
|
| 1026 |
+
border-left-color: #ff6b6b;
|
| 1027 |
+
}
|
| 1028 |
+
|
| 1029 |
+
.callout-box.warning .callout-header {
|
| 1030 |
+
color: #ff6b6b;
|
| 1031 |
+
}
|
| 1032 |
+
|
| 1033 |
+
.callout-box.tip {
|
| 1034 |
+
background: rgba(81, 207, 102, 0.1);
|
| 1035 |
+
border-left-color: #51cf66;
|
| 1036 |
+
}
|
| 1037 |
+
|
| 1038 |
+
.callout-box.tip .callout-header {
|
| 1039 |
+
color: #51cf66;
|
| 1040 |
+
}
|
| 1041 |
+
|
| 1042 |
+
.callout-box.example {
|
| 1043 |
+
background: rgba(74, 144, 226, 0.1);
|
| 1044 |
+
border-left-color: #4a90e2;
|
| 1045 |
+
}
|
| 1046 |
+
|
| 1047 |
+
.callout-box.example .callout-header {
|
| 1048 |
+
color: #4a90e2;
|
| 1049 |
+
}
|
| 1050 |
+
|
| 1051 |
+
.callout-box p,
|
| 1052 |
+
.callout-box ul,
|
| 1053 |
+
.callout-box ol {
|
| 1054 |
+
color: #d0d0d0;
|
| 1055 |
+
}
|
| 1056 |
+
|
| 1057 |
+
/* Formula Cards */
|
| 1058 |
+
.formula-card {
|
| 1059 |
+
background: linear-gradient(135deg, #0f3460 0%, #16213e 100%);
|
| 1060 |
+
padding: 2rem;
|
| 1061 |
+
border-radius: 12px;
|
| 1062 |
+
margin-bottom: 1.5rem;
|
| 1063 |
+
border: 2px solid #4a90e2;
|
| 1064 |
+
box-shadow: 0 4px 20px rgba(74, 144, 226, 0.2);
|
| 1065 |
+
}
|
| 1066 |
+
|
| 1067 |
+
.formula-header {
|
| 1068 |
+
color: #64ffda;
|
| 1069 |
+
font-size: 1.2rem;
|
| 1070 |
+
font-weight: 700;
|
| 1071 |
+
margin-bottom: 1rem;
|
| 1072 |
+
text-align: center;
|
| 1073 |
+
text-transform: uppercase;
|
| 1074 |
+
letter-spacing: 1px;
|
| 1075 |
+
}
|
| 1076 |
+
|
| 1077 |
+
.formula-main {
|
| 1078 |
+
font-size: 1.8rem;
|
| 1079 |
+
text-align: center;
|
| 1080 |
+
margin: 1.5rem 0;
|
| 1081 |
+
color: #fff;
|
| 1082 |
+
font-family: 'Courier New', monospace;
|
| 1083 |
+
}
|
| 1084 |
+
|
| 1085 |
+
.formula-symbol {
|
| 1086 |
+
color: #64ffda;
|
| 1087 |
+
font-weight: 700;
|
| 1088 |
+
font-size: 2rem;
|
| 1089 |
+
}
|
| 1090 |
+
|
| 1091 |
+
.formula-var {
|
| 1092 |
+
color: #64ffda;
|
| 1093 |
+
font-weight: 600;
|
| 1094 |
+
}
|
| 1095 |
+
|
| 1096 |
+
.formula-fraction {
|
| 1097 |
+
display: inline-flex;
|
| 1098 |
+
flex-direction: column;
|
| 1099 |
+
align-items: center;
|
| 1100 |
+
margin: 0 0.5rem;
|
| 1101 |
+
vertical-align: middle;
|
| 1102 |
+
}
|
| 1103 |
+
|
| 1104 |
+
.formula-numerator,
|
| 1105 |
+
.formula-denominator {
|
| 1106 |
+
padding: 0.2rem 0.5rem;
|
| 1107 |
+
}
|
| 1108 |
+
|
| 1109 |
+
.formula-line {
|
| 1110 |
+
width: 100%;
|
| 1111 |
+
height: 2px;
|
| 1112 |
+
background: #fff;
|
| 1113 |
+
margin: 0.2rem 0;
|
| 1114 |
+
}
|
| 1115 |
+
|
| 1116 |
+
.formula-steps {
|
| 1117 |
+
margin-top: 1rem;
|
| 1118 |
+
padding-top: 1rem;
|
| 1119 |
+
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
| 1120 |
+
}
|
| 1121 |
+
|
| 1122 |
+
.formula-steps p {
|
| 1123 |
+
color: #a0a0a0;
|
| 1124 |
+
margin-bottom: 0.5rem;
|
| 1125 |
+
}
|
| 1126 |
+
|
| 1127 |
+
.formula-steps ol,
|
| 1128 |
+
.formula-steps ul {
|
| 1129 |
+
margin-left: 2rem;
|
| 1130 |
+
color: #d0d0d0;
|
| 1131 |
+
}
|
| 1132 |
+
|
| 1133 |
+
.formula-steps li {
|
| 1134 |
+
margin-bottom: 0.5rem;
|
| 1135 |
+
}
|
| 1136 |
+
|
| 1137 |
+
/* Interactive Container */
|
| 1138 |
+
.interactive-container {
|
| 1139 |
+
background: #16213e;
|
| 1140 |
+
padding: 2rem;
|
| 1141 |
+
border-radius: 12px;
|
| 1142 |
+
margin-bottom: 2rem;
|
| 1143 |
+
border: 2px solid #4a90e2;
|
| 1144 |
+
box-shadow: 0 4px 20px rgba(74, 144, 226, 0.3);
|
| 1145 |
+
}
|
| 1146 |
+
|
| 1147 |
+
.interactive-container h3 {
|
| 1148 |
+
color: #64ffda;
|
| 1149 |
+
margin-bottom: 1.5rem;
|
| 1150 |
+
text-align: center;
|
| 1151 |
+
font-size: 1.5rem;
|
| 1152 |
+
}
|
| 1153 |
+
|
| 1154 |
+
.interactive-container canvas {
|
| 1155 |
+
display: block;
|
| 1156 |
+
max-width: 100%;
|
| 1157 |
+
height: auto;
|
| 1158 |
+
margin: 0 auto 1.5rem;
|
| 1159 |
+
background: #0f3460;
|
| 1160 |
+
border-radius: 8px;
|
| 1161 |
+
border: 1px solid #4a90e2;
|
| 1162 |
+
}
|
| 1163 |
+
|
| 1164 |
+
/* Controls */
|
| 1165 |
+
.controls {
|
| 1166 |
+
display: flex;
|
| 1167 |
+
flex-direction: column;
|
| 1168 |
+
gap: 1rem;
|
| 1169 |
+
align-items: center;
|
| 1170 |
+
}
|
| 1171 |
+
|
| 1172 |
+
.input-group {
|
| 1173 |
+
display: flex;
|
| 1174 |
+
flex-direction: column;
|
| 1175 |
+
gap: 0.8rem;
|
| 1176 |
+
width: 100%;
|
| 1177 |
+
max-width: 600px;
|
| 1178 |
+
}
|
| 1179 |
+
|
| 1180 |
+
.input-group label {
|
| 1181 |
+
color: #64ffda;
|
| 1182 |
+
font-weight: 600;
|
| 1183 |
+
}
|
| 1184 |
+
|
| 1185 |
+
.form-control {
|
| 1186 |
+
padding: 0.8rem;
|
| 1187 |
+
background: #0f3460;
|
| 1188 |
+
border: 2px solid #4a90e2;
|
| 1189 |
+
border-radius: 8px;
|
| 1190 |
+
color: #e1e1e1;
|
| 1191 |
+
font-size: 1rem;
|
| 1192 |
+
transition: all 0.3s ease;
|
| 1193 |
+
}
|
| 1194 |
+
|
| 1195 |
+
.form-control:focus {
|
| 1196 |
+
outline: none;
|
| 1197 |
+
border-color: #64ffda;
|
| 1198 |
+
box-shadow: 0 0 10px rgba(100, 255, 218, 0.3);
|
| 1199 |
+
}
|
| 1200 |
+
|
| 1201 |
+
.slider-group {
|
| 1202 |
+
display: flex;
|
| 1203 |
+
flex-direction: column;
|
| 1204 |
+
gap: 0.5rem;
|
| 1205 |
+
width: 100%;
|
| 1206 |
+
}
|
| 1207 |
+
|
| 1208 |
+
.slider-group label {
|
| 1209 |
+
color: #64ffda;
|
| 1210 |
+
font-weight: 600;
|
| 1211 |
+
}
|
| 1212 |
+
|
| 1213 |
+
.slider {
|
| 1214 |
+
width: 100%;
|
| 1215 |
+
height: 8px;
|
| 1216 |
+
border-radius: 5px;
|
| 1217 |
+
background: #0f3460;
|
| 1218 |
+
outline: none;
|
| 1219 |
+
-webkit-appearance: none;
|
| 1220 |
+
}
|
| 1221 |
+
|
| 1222 |
+
.slider::-webkit-slider-thumb {
|
| 1223 |
+
-webkit-appearance: none;
|
| 1224 |
+
appearance: none;
|
| 1225 |
+
width: 20px;
|
| 1226 |
+
height: 20px;
|
| 1227 |
+
border-radius: 50%;
|
| 1228 |
+
background: #64ffda;
|
| 1229 |
+
cursor: pointer;
|
| 1230 |
+
box-shadow: 0 0 10px rgba(100, 255, 218, 0.5);
|
| 1231 |
+
transition: all 0.3s ease;
|
| 1232 |
+
}
|
| 1233 |
+
|
| 1234 |
+
.slider::-webkit-slider-thumb:hover {
|
| 1235 |
+
background: #4a90e2;
|
| 1236 |
+
transform: scale(1.2);
|
| 1237 |
+
}
|
| 1238 |
+
|
| 1239 |
+
.slider::-moz-range-thumb {
|
| 1240 |
+
width: 20px;
|
| 1241 |
+
height: 20px;
|
| 1242 |
+
border-radius: 50%;
|
| 1243 |
+
background: #64ffda;
|
| 1244 |
+
cursor: pointer;
|
| 1245 |
+
border: none;
|
| 1246 |
+
box-shadow: 0 0 10px rgba(100, 255, 218, 0.5);
|
| 1247 |
+
}
|
| 1248 |
+
|
| 1249 |
+
/* Buttons */
|
| 1250 |
+
.btn {
|
| 1251 |
+
padding: 0.8rem 2rem;
|
| 1252 |
+
border: none;
|
| 1253 |
+
border-radius: 8px;
|
| 1254 |
+
font-size: 1rem;
|
| 1255 |
+
font-weight: 600;
|
| 1256 |
+
cursor: pointer;
|
| 1257 |
+
transition: all 0.3s ease;
|
| 1258 |
+
text-transform: uppercase;
|
| 1259 |
+
letter-spacing: 1px;
|
| 1260 |
+
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
|
| 1261 |
+
}
|
| 1262 |
+
|
| 1263 |
+
.btn-primary {
|
| 1264 |
+
background: linear-gradient(135deg, #4a90e2, #64ffda);
|
| 1265 |
+
color: #1a1a2e;
|
| 1266 |
+
}
|
| 1267 |
+
|
| 1268 |
+
.btn-primary:hover {
|
| 1269 |
+
transform: translateY(-2px);
|
| 1270 |
+
box-shadow: 0 6px 20px rgba(100, 255, 218, 0.4);
|
| 1271 |
+
}
|
| 1272 |
+
|
| 1273 |
+
.btn-secondary {
|
| 1274 |
+
background: #0f3460;
|
| 1275 |
+
color: #64ffda;
|
| 1276 |
+
border: 2px solid #4a90e2;
|
| 1277 |
+
}
|
| 1278 |
+
|
| 1279 |
+
.btn-secondary:hover {
|
| 1280 |
+
background: #16213e;
|
| 1281 |
+
transform: translateY(-2px);
|
| 1282 |
+
}
|
| 1283 |
+
|
| 1284 |
+
/* Results Display */
|
| 1285 |
+
.results {
|
| 1286 |
+
display: grid;
|
| 1287 |
+
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
| 1288 |
+
gap: 1rem;
|
| 1289 |
+
width: 100%;
|
| 1290 |
+
margin-top: 1rem;
|
| 1291 |
+
}
|
| 1292 |
+
|
| 1293 |
+
.result-item {
|
| 1294 |
+
background: #0f3460;
|
| 1295 |
+
padding: 1rem;
|
| 1296 |
+
border-radius: 8px;
|
| 1297 |
+
text-align: center;
|
| 1298 |
+
border: 2px solid #4a90e2;
|
| 1299 |
+
}
|
| 1300 |
+
|
| 1301 |
+
.result-label {
|
| 1302 |
+
display: block;
|
| 1303 |
+
color: #64ffda;
|
| 1304 |
+
font-weight: 600;
|
| 1305 |
+
margin-bottom: 0.5rem;
|
| 1306 |
+
font-size: 0.9rem;
|
| 1307 |
+
}
|
| 1308 |
+
|
| 1309 |
+
.result-item span:last-child {
|
| 1310 |
+
display: block;
|
| 1311 |
+
color: #fff;
|
| 1312 |
+
font-size: 1.5rem;
|
| 1313 |
+
font-weight: 700;
|
| 1314 |
+
}
|
| 1315 |
+
|
| 1316 |
+
/* Tables */
|
| 1317 |
+
.comparison-table {
|
| 1318 |
+
width: 100%;
|
| 1319 |
+
border-collapse: collapse;
|
| 1320 |
+
margin: 1rem 0;
|
| 1321 |
+
background: #0f3460;
|
| 1322 |
+
border-radius: 8px;
|
| 1323 |
+
overflow: hidden;
|
| 1324 |
+
}
|
| 1325 |
+
|
| 1326 |
+
.comparison-table thead {
|
| 1327 |
+
background: linear-gradient(135deg, #4a90e2, #64ffda);
|
| 1328 |
+
color: #1a1a2e;
|
| 1329 |
+
}
|
| 1330 |
+
|
| 1331 |
+
.comparison-table th,
|
| 1332 |
+
.comparison-table td {
|
| 1333 |
+
padding: 1rem;
|
| 1334 |
+
text-align: left;
|
| 1335 |
+
border-bottom: 1px solid #16213e;
|
| 1336 |
+
}
|
| 1337 |
+
|
| 1338 |
+
.comparison-table th {
|
| 1339 |
+
font-weight: 700;
|
| 1340 |
+
text-transform: uppercase;
|
| 1341 |
+
font-size: 0.9rem;
|
| 1342 |
+
letter-spacing: 1px;
|
| 1343 |
+
}
|
| 1344 |
+
|
| 1345 |
+
.comparison-table tbody tr {
|
| 1346 |
+
transition: background 0.3s ease;
|
| 1347 |
+
}
|
| 1348 |
+
|
| 1349 |
+
.comparison-table tbody tr:hover {
|
| 1350 |
+
background: rgba(74, 144, 226, 0.1);
|
| 1351 |
+
}
|
| 1352 |
+
|
| 1353 |
+
.comparison-table td {
|
| 1354 |
+
color: #d0d0d0;
|
| 1355 |
+
}
|
| 1356 |
+
|
| 1357 |
+
/* Two Column Layout */
|
| 1358 |
+
.two-column {
|
| 1359 |
+
display: grid;
|
| 1360 |
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
| 1361 |
+
gap: 2rem;
|
| 1362 |
+
margin: 1.5rem 0;
|
| 1363 |
+
}
|
| 1364 |
+
|
| 1365 |
+
.column {
|
| 1366 |
+
background: #0f3460;
|
| 1367 |
+
padding: 1.5rem;
|
| 1368 |
+
border-radius: 8px;
|
| 1369 |
+
border: 2px solid rgba(74, 144, 226, 0.3);
|
| 1370 |
+
}
|
| 1371 |
+
|
| 1372 |
+
/* Comparison Grid */
|
| 1373 |
+
.comparison-grid {
|
| 1374 |
+
display: grid;
|
| 1375 |
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
| 1376 |
+
gap: 1.5rem;
|
| 1377 |
+
margin: 1.5rem 0;
|
| 1378 |
+
}
|
| 1379 |
+
|
| 1380 |
+
.comparison-item {
|
| 1381 |
+
background: #0f3460;
|
| 1382 |
+
padding: 1.5rem;
|
| 1383 |
+
border-radius: 8px;
|
| 1384 |
+
border-left: 4px solid #4a90e2;
|
| 1385 |
+
}
|
| 1386 |
+
|
| 1387 |
+
/* Data Tree */
|
| 1388 |
+
.data-tree {
|
| 1389 |
+
display: flex;
|
| 1390 |
+
flex-direction: column;
|
| 1391 |
+
align-items: center;
|
| 1392 |
+
gap: 2rem;
|
| 1393 |
+
padding: 2rem;
|
| 1394 |
+
margin: 1.5rem 0;
|
| 1395 |
+
}
|
| 1396 |
+
|
| 1397 |
+
.tree-level-1,
|
| 1398 |
+
.tree-level-2,
|
| 1399 |
+
.tree-level-3 {
|
| 1400 |
+
display: flex;
|
| 1401 |
+
gap: 2rem;
|
| 1402 |
+
justify-content: center;
|
| 1403 |
+
flex-wrap: wrap;
|
| 1404 |
+
}
|
| 1405 |
+
|
| 1406 |
+
.tree-node {
|
| 1407 |
+
padding: 1rem 2rem;
|
| 1408 |
+
background: #0f3460;
|
| 1409 |
+
border: 2px solid #4a90e2;
|
| 1410 |
+
border-radius: 8px;
|
| 1411 |
+
color: #64ffda;
|
| 1412 |
+
font-weight: 600;
|
| 1413 |
+
position: relative;
|
| 1414 |
+
transition: all 0.3s ease;
|
| 1415 |
+
}
|
| 1416 |
+
|
| 1417 |
+
.tree-node:hover {
|
| 1418 |
+
transform: scale(1.05);
|
| 1419 |
+
box-shadow: 0 4px 15px rgba(74, 144, 226, 0.4);
|
| 1420 |
+
}
|
| 1421 |
+
|
| 1422 |
+
.tree-node.main {
|
| 1423 |
+
font-size: 1.3rem;
|
| 1424 |
+
background: linear-gradient(135deg, #4a90e2, #64ffda);
|
| 1425 |
+
color: #1a1a2e;
|
| 1426 |
+
}
|
| 1427 |
+
|
| 1428 |
+
.tree-node.categorical {
|
| 1429 |
+
border-color: #64ffda;
|
| 1430 |
+
}
|
| 1431 |
+
|
| 1432 |
+
.tree-node.numerical {
|
| 1433 |
+
border-color: #ff6b6b;
|
| 1434 |
+
}
|
| 1435 |
+
|
| 1436 |
+
/* Use Case List */
|
| 1437 |
+
.use-case-list {
|
| 1438 |
+
list-style: none;
|
| 1439 |
+
margin-left: 0;
|
| 1440 |
+
}
|
| 1441 |
+
|
| 1442 |
+
.use-case-list li {
|
| 1443 |
+
padding: 1rem;
|
| 1444 |
+
margin-bottom: 1rem;
|
| 1445 |
+
background: #0f3460;
|
| 1446 |
+
border-radius: 8px;
|
| 1447 |
+
border-left: 4px solid #4a90e2;
|
| 1448 |
+
transition: all 0.3s ease;
|
| 1449 |
+
}
|
| 1450 |
+
|
| 1451 |
+
.use-case-list li:hover {
|
| 1452 |
+
transform: translateX(5px);
|
| 1453 |
+
border-left-color: #64ffda;
|
| 1454 |
+
}
|
| 1455 |
+
|
| 1456 |
+
/* Example Solution */
|
| 1457 |
+
.example-solution {
|
| 1458 |
+
background: #0f3460;
|
| 1459 |
+
padding: 1.5rem;
|
| 1460 |
+
border-radius: 8px;
|
| 1461 |
+
margin-top: 1rem;
|
| 1462 |
+
font-family: 'Courier New', monospace;
|
| 1463 |
+
}
|
| 1464 |
+
|
| 1465 |
+
.example-solution p {
|
| 1466 |
+
margin-bottom: 0.8rem;
|
| 1467 |
+
color: #d0d0d0;
|
| 1468 |
+
}
|
| 1469 |
+
|
| 1470 |
+
.example-solution strong {
|
| 1471 |
+
color: #64ffda;
|
| 1472 |
+
}
|
| 1473 |
+
|
| 1474 |
+
/* Summary Card */
|
| 1475 |
+
.summary-card {
|
| 1476 |
+
background: linear-gradient(135deg, #0f3460 0%, #16213e 100%);
|
| 1477 |
+
padding: 2rem;
|
| 1478 |
+
border-radius: 12px;
|
| 1479 |
+
border: 2px solid #64ffda;
|
| 1480 |
+
box-shadow: 0 4px 20px rgba(100, 255, 218, 0.3);
|
| 1481 |
+
margin-bottom: 2rem;
|
| 1482 |
+
}
|
| 1483 |
+
|
| 1484 |
+
.summary-card h3 {
|
| 1485 |
+
color: #64ffda;
|
| 1486 |
+
margin-bottom: 1rem;
|
| 1487 |
+
font-size: 1.5rem;
|
| 1488 |
+
text-align: center;
|
| 1489 |
+
}
|
| 1490 |
+
|
| 1491 |
+
.summary-card ul {
|
| 1492 |
+
list-style: none;
|
| 1493 |
+
margin-left: 0;
|
| 1494 |
+
}
|
| 1495 |
+
|
| 1496 |
+
.summary-card li {
|
| 1497 |
+
padding: 0.8rem;
|
| 1498 |
+
margin-bottom: 0.8rem;
|
| 1499 |
+
background: rgba(100, 255, 218, 0.05);
|
| 1500 |
+
border-radius: 6px;
|
| 1501 |
+
border-left: 3px solid #64ffda;
|
| 1502 |
+
color: #d0d0d0;
|
| 1503 |
+
}
|
| 1504 |
+
|
| 1505 |
+
.summary-card li::before {
|
| 1506 |
+
content: "β";
|
| 1507 |
+
color: #64ffda;
|
| 1508 |
+
font-weight: 700;
|
| 1509 |
+
margin-right: 0.8rem;
|
| 1510 |
+
}
|
| 1511 |
+
|
| 1512 |
+
/* Data Examples Table */
|
| 1513 |
+
.data-examples-table {
|
| 1514 |
+
width: 100%;
|
| 1515 |
+
border-collapse: collapse;
|
| 1516 |
+
margin-top: 1rem;
|
| 1517 |
+
}
|
| 1518 |
+
|
| 1519 |
+
.data-examples-table th,
|
| 1520 |
+
.data-examples-table td {
|
| 1521 |
+
padding: 1rem;
|
| 1522 |
+
text-align: left;
|
| 1523 |
+
border-bottom: 1px solid rgba(74, 144, 226, 0.2);
|
| 1524 |
+
}
|
| 1525 |
+
|
| 1526 |
+
.data-examples-table th {
|
| 1527 |
+
background: rgba(74, 144, 226, 0.2);
|
| 1528 |
+
color: #64ffda;
|
| 1529 |
+
font-weight: 600;
|
| 1530 |
+
}
|
| 1531 |
+
|
| 1532 |
+
/* Responsive Design */
|
| 1533 |
+
@media (max-width: 1024px) {
|
| 1534 |
+
.main-container {
|
| 1535 |
+
flex-direction: column;
|
| 1536 |
+
}
|
| 1537 |
+
|
| 1538 |
+
.sidebar {
|
| 1539 |
+
width: 100%;
|
| 1540 |
+
height: auto;
|
| 1541 |
+
position: static;
|
| 1542 |
+
transform: translateX(-100%);
|
| 1543 |
+
}
|
| 1544 |
+
|
| 1545 |
+
.sidebar.active {
|
| 1546 |
+
transform: translateX(0);
|
| 1547 |
+
}
|
| 1548 |
+
|
| 1549 |
+
.mobile-menu-btn {
|
| 1550 |
+
display: flex;
|
| 1551 |
+
}
|
| 1552 |
+
|
| 1553 |
+
.content {
|
| 1554 |
+
padding: 2rem 1.5rem;
|
| 1555 |
+
}
|
| 1556 |
+
|
| 1557 |
+
.topic-header h2 {
|
| 1558 |
+
font-size: 2rem;
|
| 1559 |
+
}
|
| 1560 |
+
|
| 1561 |
+
.two-column {
|
| 1562 |
+
grid-template-columns: 1fr;
|
| 1563 |
+
}
|
| 1564 |
+
}
|
| 1565 |
+
|
| 1566 |
+
@media (max-width: 768px) {
|
| 1567 |
+
.course-title {
|
| 1568 |
+
font-size: 1.3rem;
|
| 1569 |
+
}
|
| 1570 |
+
|
| 1571 |
+
.content {
|
| 1572 |
+
padding: 1.5rem 1rem;
|
| 1573 |
+
}
|
| 1574 |
+
|
| 1575 |
+
.topic-header h2 {
|
| 1576 |
+
font-size: 1.6rem;
|
| 1577 |
+
}
|
| 1578 |
+
|
| 1579 |
+
.formula-main {
|
| 1580 |
+
font-size: 1.3rem;
|
| 1581 |
+
}
|
| 1582 |
+
|
| 1583 |
+
.comparison-grid {
|
| 1584 |
+
grid-template-columns: 1fr;
|
| 1585 |
+
}
|
| 1586 |
+
|
| 1587 |
+
.results {
|
| 1588 |
+
grid-template-columns: 1fr;
|
| 1589 |
+
}
|
| 1590 |
+
|
| 1591 |
+
.interactive-container canvas {
|
| 1592 |
+
max-width: 100%;
|
| 1593 |
+
height: auto;
|
| 1594 |
+
}
|
| 1595 |
+
}
|
| 1596 |
+
|
| 1597 |
+
/* Animations */
|
| 1598 |
+
@keyframes pulse {
|
| 1599 |
+
0%, 100% {
|
| 1600 |
+
opacity: 1;
|
| 1601 |
+
}
|
| 1602 |
+
50% {
|
| 1603 |
+
opacity: 0.5;
|
| 1604 |
+
}
|
| 1605 |
+
}
|
| 1606 |
+
|
| 1607 |
+
.pulse {
|
| 1608 |
+
animation: pulse 2s ease-in-out infinite;
|
| 1609 |
+
}
|
| 1610 |
+
|
| 1611 |
+
/* Loading State */
|
| 1612 |
+
.loading {
|
| 1613 |
+
display: inline-block;
|
| 1614 |
+
width: 20px;
|
| 1615 |
+
height: 20px;
|
| 1616 |
+
border: 3px solid rgba(100, 255, 218, 0.3);
|
| 1617 |
+
border-radius: 50%;
|
| 1618 |
+
border-top-color: #64ffda;
|
| 1619 |
+
animation: spin 1s ease-in-out infinite;
|
| 1620 |
+
}
|
| 1621 |
+
|
| 1622 |
+
@keyframes spin {
|
| 1623 |
+
to {
|
| 1624 |
+
transform: rotate(360deg);
|
| 1625 |
+
}
|
| 1626 |
+
}
|
| 1627 |
+
|
| 1628 |
+
/* Smooth Transitions */
|
| 1629 |
+
* {
|
| 1630 |
+
transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease;
|
| 1631 |
+
}
|
ml_complete-all-topics/app.js
CHANGED
|
@@ -104,6 +104,9 @@ function initSections() {
|
|
| 104 |
if (section.id === 'cross-validation') initCrossValidation();
|
| 105 |
if (section.id === 'preprocessing') initPreprocessing();
|
| 106 |
if (section.id === 'loss-functions') initLossFunctions();
|
|
|
|
|
|
|
|
|
|
| 107 |
}
|
| 108 |
});
|
| 109 |
});
|
|
@@ -2351,6 +2354,334 @@ function drawLossCurves() {
|
|
| 2351 |
ctx.restore();
|
| 2352 |
}
|
| 2353 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2354 |
// Handle window resize
|
| 2355 |
let resizeTimer;
|
| 2356 |
window.addEventListener('resize', () => {
|
|
@@ -2377,5 +2708,8 @@ window.addEventListener('resize', () => {
|
|
| 2377 |
drawSVMCParameter();
|
| 2378 |
drawSVMTraining();
|
| 2379 |
drawSVMKernel();
|
|
|
|
|
|
|
|
|
|
| 2380 |
}, 250);
|
| 2381 |
});
|
|
|
|
| 104 |
if (section.id === 'cross-validation') initCrossValidation();
|
| 105 |
if (section.id === 'preprocessing') initPreprocessing();
|
| 106 |
if (section.id === 'loss-functions') initLossFunctions();
|
| 107 |
+
if (section.id === 'optimal-k') initOptimalK();
|
| 108 |
+
if (section.id === 'hyperparameter-tuning') initHyperparameterTuning();
|
| 109 |
+
if (section.id === 'naive-bayes') initNaiveBayes();
|
| 110 |
}
|
| 111 |
});
|
| 112 |
});
|
|
|
|
| 2354 |
ctx.restore();
|
| 2355 |
}
|
| 2356 |
|
| 2357 |
+
// Optimal K for KNN
|
| 2358 |
+
function initOptimalK() {
|
| 2359 |
+
const canvas = document.getElementById('optimal-k-canvas');
|
| 2360 |
+
if (!canvas || canvas.dataset.initialized) return;
|
| 2361 |
+
canvas.dataset.initialized = 'true';
|
| 2362 |
+
|
| 2363 |
+
const rangeSlider = document.getElementById('k-range-slider');
|
| 2364 |
+
const foldsSlider = document.getElementById('cv-folds-slider');
|
| 2365 |
+
|
| 2366 |
+
if (rangeSlider) {
|
| 2367 |
+
rangeSlider.addEventListener('input', (e) => {
|
| 2368 |
+
document.getElementById('k-range-val').textContent = e.target.value;
|
| 2369 |
+
drawOptimalK();
|
| 2370 |
+
});
|
| 2371 |
+
}
|
| 2372 |
+
|
| 2373 |
+
if (foldsSlider) {
|
| 2374 |
+
foldsSlider.addEventListener('input', (e) => {
|
| 2375 |
+
document.getElementById('cv-folds-val').textContent = e.target.value;
|
| 2376 |
+
drawOptimalK();
|
| 2377 |
+
});
|
| 2378 |
+
}
|
| 2379 |
+
|
| 2380 |
+
drawOptimalK();
|
| 2381 |
+
}
|
| 2382 |
+
|
| 2383 |
+
function drawOptimalK() {
|
| 2384 |
+
const canvas = document.getElementById('optimal-k-canvas');
|
| 2385 |
+
if (!canvas) return;
|
| 2386 |
+
|
| 2387 |
+
const ctx = canvas.getContext('2d');
|
| 2388 |
+
const width = canvas.width = canvas.offsetWidth;
|
| 2389 |
+
const height = canvas.height = 400;
|
| 2390 |
+
|
| 2391 |
+
ctx.clearRect(0, 0, width, height);
|
| 2392 |
+
ctx.fillStyle = '#1a2332';
|
| 2393 |
+
ctx.fillRect(0, 0, width, height);
|
| 2394 |
+
|
| 2395 |
+
const padding = 60;
|
| 2396 |
+
const chartWidth = width - 2 * padding;
|
| 2397 |
+
const chartHeight = height - 2 * padding;
|
| 2398 |
+
|
| 2399 |
+
// Use provided data
|
| 2400 |
+
const kRange = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
|
| 2401 |
+
const accuracies = [0.85, 0.88, 0.92, 0.94, 0.96, 0.97, 0.98, 0.97, 0.96, 0.95, 0.94, 0.93, 0.92, 0.91, 0.90, 0.89, 0.88, 0.87, 0.86, 0.85];
|
| 2402 |
+
const optimalK = 7;
|
| 2403 |
+
|
| 2404 |
+
const scaleX = (k) => padding + ((k - 1) / 19) * chartWidth;
|
| 2405 |
+
const scaleY = (acc) => height - padding - ((acc - 0.8) / 0.2) * chartHeight;
|
| 2406 |
+
|
| 2407 |
+
// Draw grid
|
| 2408 |
+
ctx.strokeStyle = 'rgba(42, 53, 68, 0.5)';
|
| 2409 |
+
ctx.lineWidth = 1;
|
| 2410 |
+
for (let i = 0; i <= 10; i++) {
|
| 2411 |
+
const x = padding + (chartWidth / 10) * i;
|
| 2412 |
+
ctx.beginPath();
|
| 2413 |
+
ctx.moveTo(x, padding);
|
| 2414 |
+
ctx.lineTo(x, height - padding);
|
| 2415 |
+
ctx.stroke();
|
| 2416 |
+
|
| 2417 |
+
const y = padding + (chartHeight / 10) * i;
|
| 2418 |
+
ctx.beginPath();
|
| 2419 |
+
ctx.moveTo(padding, y);
|
| 2420 |
+
ctx.lineTo(width - padding, y);
|
| 2421 |
+
ctx.stroke();
|
| 2422 |
+
}
|
| 2423 |
+
|
| 2424 |
+
// Draw axes
|
| 2425 |
+
ctx.strokeStyle = '#2a3544';
|
| 2426 |
+
ctx.lineWidth = 2;
|
| 2427 |
+
ctx.beginPath();
|
| 2428 |
+
ctx.moveTo(padding, padding);
|
| 2429 |
+
ctx.lineTo(padding, height - padding);
|
| 2430 |
+
ctx.lineTo(width - padding, height - padding);
|
| 2431 |
+
ctx.stroke();
|
| 2432 |
+
|
| 2433 |
+
// Draw line
|
| 2434 |
+
ctx.strokeStyle = '#6aa9ff';
|
| 2435 |
+
ctx.lineWidth = 3;
|
| 2436 |
+
ctx.beginPath();
|
| 2437 |
+
kRange.forEach((k, i) => {
|
| 2438 |
+
const x = scaleX(k);
|
| 2439 |
+
const y = scaleY(accuracies[i]);
|
| 2440 |
+
if (i === 0) ctx.moveTo(x, y);
|
| 2441 |
+
else ctx.lineTo(x, y);
|
| 2442 |
+
});
|
| 2443 |
+
ctx.stroke();
|
| 2444 |
+
|
| 2445 |
+
// Draw points
|
| 2446 |
+
kRange.forEach((k, i) => {
|
| 2447 |
+
const x = scaleX(k);
|
| 2448 |
+
const y = scaleY(accuracies[i]);
|
| 2449 |
+
const isOptimal = k === optimalK;
|
| 2450 |
+
|
| 2451 |
+
ctx.fillStyle = isOptimal ? '#7ef0d4' : '#6aa9ff';
|
| 2452 |
+
ctx.beginPath();
|
| 2453 |
+
ctx.arc(x, y, isOptimal ? 8 : 5, 0, 2 * Math.PI);
|
| 2454 |
+
ctx.fill();
|
| 2455 |
+
|
| 2456 |
+
if (isOptimal) {
|
| 2457 |
+
ctx.strokeStyle = '#7ef0d4';
|
| 2458 |
+
ctx.lineWidth = 2;
|
| 2459 |
+
ctx.beginPath();
|
| 2460 |
+
ctx.arc(x, y, 14, 0, 2 * Math.PI);
|
| 2461 |
+
ctx.stroke();
|
| 2462 |
+
|
| 2463 |
+
// Label
|
| 2464 |
+
ctx.fillStyle = '#7ef0d4';
|
| 2465 |
+
ctx.font = 'bold 14px sans-serif';
|
| 2466 |
+
ctx.textAlign = 'center';
|
| 2467 |
+
ctx.fillText(`Optimal K=${optimalK}`, x, y - 25);
|
| 2468 |
+
ctx.fillText(`Accuracy: ${(accuracies[i] * 100).toFixed(1)}%`, x, y - 10);
|
| 2469 |
+
}
|
| 2470 |
+
});
|
| 2471 |
+
|
| 2472 |
+
// Draw vertical line at optimal K
|
| 2473 |
+
ctx.strokeStyle = 'rgba(126, 240, 212, 0.3)';
|
| 2474 |
+
ctx.lineWidth = 2;
|
| 2475 |
+
ctx.setLineDash([5, 5]);
|
| 2476 |
+
ctx.beginPath();
|
| 2477 |
+
ctx.moveTo(scaleX(optimalK), padding);
|
| 2478 |
+
ctx.lineTo(scaleX(optimalK), height - padding);
|
| 2479 |
+
ctx.stroke();
|
| 2480 |
+
ctx.setLineDash([]);
|
| 2481 |
+
|
| 2482 |
+
// Labels
|
| 2483 |
+
ctx.fillStyle = '#a9b4c2';
|
| 2484 |
+
ctx.font = '12px sans-serif';
|
| 2485 |
+
ctx.textAlign = 'center';
|
| 2486 |
+
ctx.fillText('K Value', width / 2, height - 20);
|
| 2487 |
+
ctx.save();
|
| 2488 |
+
ctx.translate(20, height / 2);
|
| 2489 |
+
ctx.rotate(-Math.PI / 2);
|
| 2490 |
+
ctx.fillText('Mean Accuracy', 0, 0);
|
| 2491 |
+
ctx.restore();
|
| 2492 |
+
|
| 2493 |
+
// X-axis labels
|
| 2494 |
+
for (let i = 1; i <= 20; i += 2) {
|
| 2495 |
+
ctx.fillText(i, scaleX(i), height - padding + 20);
|
| 2496 |
+
}
|
| 2497 |
+
}
|
| 2498 |
+
|
| 2499 |
+
// Hyperparameter Tuning & GridSearch
|
| 2500 |
+
function initHyperparameterTuning() {
|
| 2501 |
+
const canvas = document.getElementById('gridsearch-canvas');
|
| 2502 |
+
if (!canvas || canvas.dataset.initialized) return;
|
| 2503 |
+
canvas.dataset.initialized = 'true';
|
| 2504 |
+
drawGridSearch();
|
| 2505 |
+
}
|
| 2506 |
+
|
| 2507 |
+
function drawGridSearch() {
|
| 2508 |
+
const canvas = document.getElementById('gridsearch-canvas');
|
| 2509 |
+
if (!canvas) return;
|
| 2510 |
+
|
| 2511 |
+
const ctx = canvas.getContext('2d');
|
| 2512 |
+
const width = canvas.width = canvas.offsetWidth;
|
| 2513 |
+
const height = canvas.height = 400;
|
| 2514 |
+
|
| 2515 |
+
ctx.clearRect(0, 0, width, height);
|
| 2516 |
+
ctx.fillStyle = '#1a2332';
|
| 2517 |
+
ctx.fillRect(0, 0, width, height);
|
| 2518 |
+
|
| 2519 |
+
const padding = 80;
|
| 2520 |
+
const chartWidth = width - 2 * padding;
|
| 2521 |
+
const chartHeight = height - 2 * padding;
|
| 2522 |
+
|
| 2523 |
+
// Grid data - C vs gamma heatmap
|
| 2524 |
+
const cValues = [0.1, 1, 10, 100];
|
| 2525 |
+
const gammaValues = [0.001, 0.01, 0.1, 1];
|
| 2526 |
+
|
| 2527 |
+
// Scores (simulated)
|
| 2528 |
+
const scores = [
|
| 2529 |
+
[0.70, 0.75, 0.78, 0.76],
|
| 2530 |
+
[0.82, 0.88, 0.92, 0.85],
|
| 2531 |
+
[0.88, 0.95, 0.93, 0.87],
|
| 2532 |
+
[0.85, 0.90, 0.88, 0.82]
|
| 2533 |
+
];
|
| 2534 |
+
|
| 2535 |
+
const cellWidth = chartWidth / cValues.length;
|
| 2536 |
+
const cellHeight = chartHeight / gammaValues.length;
|
| 2537 |
+
|
| 2538 |
+
// Draw cells
|
| 2539 |
+
cValues.forEach((c, i) => {
|
| 2540 |
+
gammaValues.forEach((g, j) => {
|
| 2541 |
+
const x = padding + i * cellWidth;
|
| 2542 |
+
const y = padding + j * cellHeight;
|
| 2543 |
+
const score = scores[i][j];
|
| 2544 |
+
|
| 2545 |
+
// Color based on score
|
| 2546 |
+
const intensity = (score - 0.7) / 0.25;
|
| 2547 |
+
const r = Math.floor(255 - intensity * 155);
|
| 2548 |
+
const gb = Math.floor(100 + intensity * 140);
|
| 2549 |
+
ctx.fillStyle = `rgb(${r}, ${gb}, ${Math.floor(gb * 0.9)})`;
|
| 2550 |
+
ctx.fillRect(x, y, cellWidth, cellHeight);
|
| 2551 |
+
|
| 2552 |
+
// Border
|
| 2553 |
+
ctx.strokeStyle = '#1a2332';
|
| 2554 |
+
ctx.lineWidth = 2;
|
| 2555 |
+
ctx.strokeRect(x, y, cellWidth, cellHeight);
|
| 2556 |
+
|
| 2557 |
+
// Score text
|
| 2558 |
+
ctx.fillStyle = score > 0.88 ? '#1a2332' : '#e8eef6';
|
| 2559 |
+
ctx.font = 'bold 14px sans-serif';
|
| 2560 |
+
ctx.textAlign = 'center';
|
| 2561 |
+
ctx.fillText((score * 100).toFixed(0) + '%', x + cellWidth / 2, y + cellHeight / 2 + 5);
|
| 2562 |
+
|
| 2563 |
+
// Highlight best
|
| 2564 |
+
if (score === 0.95) {
|
| 2565 |
+
ctx.strokeStyle = '#7ef0d4';
|
| 2566 |
+
ctx.lineWidth = 4;
|
| 2567 |
+
ctx.strokeRect(x, y, cellWidth, cellHeight);
|
| 2568 |
+
|
| 2569 |
+
ctx.fillStyle = '#7ef0d4';
|
| 2570 |
+
ctx.font = '12px sans-serif';
|
| 2571 |
+
ctx.fillText('β
Best', x + cellWidth / 2, y + cellHeight / 2 + 22);
|
| 2572 |
+
}
|
| 2573 |
+
});
|
| 2574 |
+
});
|
| 2575 |
+
|
| 2576 |
+
// Axis labels - C
|
| 2577 |
+
ctx.fillStyle = '#a9b4c2';
|
| 2578 |
+
ctx.font = '12px sans-serif';
|
| 2579 |
+
ctx.textAlign = 'center';
|
| 2580 |
+
cValues.forEach((c, i) => {
|
| 2581 |
+
const x = padding + i * cellWidth + cellWidth / 2;
|
| 2582 |
+
ctx.fillText(`C=${c}`, x, height - padding + 25);
|
| 2583 |
+
});
|
| 2584 |
+
|
| 2585 |
+
// Axis labels - gamma
|
| 2586 |
+
ctx.textAlign = 'right';
|
| 2587 |
+
gammaValues.forEach((g, i) => {
|
| 2588 |
+
const y = padding + i * cellHeight + cellHeight / 2;
|
| 2589 |
+
ctx.fillText(`Ξ³=${g}`, padding - 10, y + 5);
|
| 2590 |
+
});
|
| 2591 |
+
|
| 2592 |
+
// Title
|
| 2593 |
+
ctx.fillStyle = '#7ef0d4';
|
| 2594 |
+
ctx.font = 'bold 16px sans-serif';
|
| 2595 |
+
ctx.textAlign = 'center';
|
| 2596 |
+
ctx.fillText('GridSearch Heatmap: C vs gamma (RBF kernel)', width / 2, 30);
|
| 2597 |
+
|
| 2598 |
+
// Legend
|
| 2599 |
+
ctx.font = '12px sans-serif';
|
| 2600 |
+
ctx.fillStyle = '#a9b4c2';
|
| 2601 |
+
ctx.textAlign = 'left';
|
| 2602 |
+
ctx.fillText('Lower accuracy', padding, height - 10);
|
| 2603 |
+
ctx.textAlign = 'right';
|
| 2604 |
+
ctx.fillText('Higher accuracy', width - padding, height - 10);
|
| 2605 |
+
}
|
| 2606 |
+
|
| 2607 |
+
// Naive Bayes
|
| 2608 |
+
function initNaiveBayes() {
|
| 2609 |
+
const canvas = document.getElementById('naive-bayes-canvas');
|
| 2610 |
+
if (!canvas || canvas.dataset.initialized) return;
|
| 2611 |
+
canvas.dataset.initialized = 'true';
|
| 2612 |
+
drawNaiveBayes();
|
| 2613 |
+
}
|
| 2614 |
+
|
| 2615 |
+
function drawNaiveBayes() {
|
| 2616 |
+
const canvas = document.getElementById('naive-bayes-canvas');
|
| 2617 |
+
if (!canvas) return;
|
| 2618 |
+
|
| 2619 |
+
const ctx = canvas.getContext('2d');
|
| 2620 |
+
const width = canvas.width = canvas.offsetWidth;
|
| 2621 |
+
const height = canvas.height = 350;
|
| 2622 |
+
|
| 2623 |
+
ctx.clearRect(0, 0, width, height);
|
| 2624 |
+
ctx.fillStyle = '#1a2332';
|
| 2625 |
+
ctx.fillRect(0, 0, width, height);
|
| 2626 |
+
|
| 2627 |
+
// Display calculation flow
|
| 2628 |
+
const steps = [
|
| 2629 |
+
{ label: 'Words', value: '["free", "money"]', color: '#6aa9ff' },
|
| 2630 |
+
{ label: 'P(free|spam)', value: '0.8', color: '#7ef0d4' },
|
| 2631 |
+
{ label: 'P(money|spam)', value: '0.7', color: '#7ef0d4' },
|
| 2632 |
+
{ label: 'P(spam)', value: '0.3', color: '#ff8c6a' },
|
| 2633 |
+
{ label: 'Likelihood', value: '0.8 Γ 0.7 = 0.56', color: '#7ef0d4' },
|
| 2634 |
+
{ label: 'Posterior', value: '0.56 Γ 0.3 = 0.168', color: '#7ef0d4' },
|
| 2635 |
+
{ label: 'Result', value: 'P(spam) = 0.98 (98%)', color: '#7ef0d4' }
|
| 2636 |
+
];
|
| 2637 |
+
|
| 2638 |
+
const boxWidth = 180;
|
| 2639 |
+
const boxHeight = 45;
|
| 2640 |
+
const startY = 40;
|
| 2641 |
+
const gap = 8;
|
| 2642 |
+
|
| 2643 |
+
steps.forEach((step, i) => {
|
| 2644 |
+
const x = (width - boxWidth) / 2;
|
| 2645 |
+
const y = startY + i * (boxHeight + gap);
|
| 2646 |
+
|
| 2647 |
+
// Box
|
| 2648 |
+
ctx.fillStyle = '#2a3544';
|
| 2649 |
+
ctx.fillRect(x, y, boxWidth, boxHeight);
|
| 2650 |
+
ctx.strokeStyle = step.color;
|
| 2651 |
+
ctx.lineWidth = 2;
|
| 2652 |
+
ctx.strokeRect(x, y, boxWidth, boxHeight);
|
| 2653 |
+
|
| 2654 |
+
// Text
|
| 2655 |
+
ctx.fillStyle = '#a9b4c2';
|
| 2656 |
+
ctx.font = '11px sans-serif';
|
| 2657 |
+
ctx.textAlign = 'center';
|
| 2658 |
+
ctx.fillText(step.label, x + boxWidth / 2, y + boxHeight / 2 - 6);
|
| 2659 |
+
|
| 2660 |
+
ctx.fillStyle = step.color;
|
| 2661 |
+
ctx.font = 'bold 13px monospace';
|
| 2662 |
+
ctx.fillText(step.value, x + boxWidth / 2, y + boxHeight / 2 + 10);
|
| 2663 |
+
|
| 2664 |
+
// Arrow
|
| 2665 |
+
if (i < steps.length - 1) {
|
| 2666 |
+
ctx.strokeStyle = '#6aa9ff';
|
| 2667 |
+
ctx.fillStyle = '#6aa9ff';
|
| 2668 |
+
ctx.lineWidth = 2;
|
| 2669 |
+
const arrowY = y + boxHeight + gap / 2;
|
| 2670 |
+
ctx.beginPath();
|
| 2671 |
+
ctx.moveTo(x + boxWidth / 2, arrowY - 3);
|
| 2672 |
+
ctx.lineTo(x + boxWidth / 2, arrowY + 3);
|
| 2673 |
+
ctx.stroke();
|
| 2674 |
+
|
| 2675 |
+
// Arrowhead
|
| 2676 |
+
ctx.beginPath();
|
| 2677 |
+
ctx.moveTo(x + boxWidth / 2, arrowY + 3);
|
| 2678 |
+
ctx.lineTo(x + boxWidth / 2 - 4, arrowY - 2);
|
| 2679 |
+
ctx.lineTo(x + boxWidth / 2 + 4, arrowY - 2);
|
| 2680 |
+
ctx.fill();
|
| 2681 |
+
}
|
| 2682 |
+
});
|
| 2683 |
+
}
|
| 2684 |
+
|
| 2685 |
// Handle window resize
|
| 2686 |
let resizeTimer;
|
| 2687 |
window.addEventListener('resize', () => {
|
|
|
|
| 2708 |
drawSVMCParameter();
|
| 2709 |
drawSVMTraining();
|
| 2710 |
drawSVMKernel();
|
| 2711 |
+
drawOptimalK();
|
| 2712 |
+
drawGridSearch();
|
| 2713 |
+
drawNaiveBayes();
|
| 2714 |
}, 250);
|
| 2715 |
});
|
ml_complete-all-topics/index.html
CHANGED
|
@@ -496,6 +496,9 @@ canvas {
|
|
| 496 |
<a href="#cross-validation" class="toc-link">10. Cross-Validation</a>
|
| 497 |
<a href="#preprocessing" class="toc-link">11. Data Preprocessing</a>
|
| 498 |
<a href="#loss-functions" class="toc-link">12. Loss Functions</a>
|
|
|
|
|
|
|
|
|
|
| 499 |
</nav>
|
| 500 |
</aside>
|
| 501 |
|
|
@@ -2378,6 +2381,514 @@ Actual Pos TP FN
|
|
| 2378 |
</div>
|
| 2379 |
</div>
|
| 2380 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2381 |
</main>
|
| 2382 |
</div>
|
| 2383 |
|
|
|
|
| 496 |
<a href="#cross-validation" class="toc-link">10. Cross-Validation</a>
|
| 497 |
<a href="#preprocessing" class="toc-link">11. Data Preprocessing</a>
|
| 498 |
<a href="#loss-functions" class="toc-link">12. Loss Functions</a>
|
| 499 |
+
<a href="#optimal-k" class="toc-link">13. Finding Optimal K for KNN</a>
|
| 500 |
+
<a href="#hyperparameter-tuning" class="toc-link">14. Hyperparameter Tuning & GridSearch</a>
|
| 501 |
+
<a href="#naive-bayes" class="toc-link">15. Naive Bayes Classifier</a>
|
| 502 |
</nav>
|
| 503 |
</aside>
|
| 504 |
|
|
|
|
| 2381 |
</div>
|
| 2382 |
</div>
|
| 2383 |
|
| 2384 |
+
<!-- Section 13: Finding Optimal K for KNN -->
|
| 2385 |
+
<div class="section" id="optimal-k">
|
| 2386 |
+
<div class="section-header">
|
| 2387 |
+
<h2>13. Finding Optimal K for KNN π―</h2>
|
| 2388 |
+
<button class="section-toggle">βΌ</button>
|
| 2389 |
+
</div>
|
| 2390 |
+
<div class="section-body">
|
| 2391 |
+
<p>In KNN, choosing the right K value is crucial! Too small = overfitting, too large = underfitting. How do we find the optimal K? Use cross-validation!</p>
|
| 2392 |
+
|
| 2393 |
+
<div class="info-card">
|
| 2394 |
+
<div class="info-card-title">The Problem</div>
|
| 2395 |
+
<ul class="info-card-list">
|
| 2396 |
+
<li>K=1: Overfits (memorizes training data, including noise)</li>
|
| 2397 |
+
<li>K=too large: Underfits (boundary too smooth, misses patterns)</li>
|
| 2398 |
+
<li>Need: K that balances bias and variance</li>
|
| 2399 |
+
<li>K controls model complexity</li>
|
| 2400 |
+
</ul>
|
| 2401 |
+
</div>
|
| 2402 |
+
|
| 2403 |
+
<h3>Why K Matters</h3>
|
| 2404 |
+
<ul>
|
| 2405 |
+
<li><strong>K controls model complexity:</strong> Small K = complex boundaries, large K = simple boundaries</li>
|
| 2406 |
+
<li><strong>Affects decision boundary smoothness:</strong> Directly impacts predictions</li>
|
| 2407 |
+
<li><strong>Impacts generalization ability:</strong> Wrong K hurts test performance</li>
|
| 2408 |
+
<li><strong>Must be chosen carefully:</strong> Can't just guess!</li>
|
| 2409 |
+
</ul>
|
| 2410 |
+
|
| 2411 |
+
<h3>The Solution: Cross-Validation</h3>
|
| 2412 |
+
<div class="formula">
|
| 2413 |
+
<strong>K-Selection Algorithm:</strong>
|
| 2414 |
+
For K = 1 to 20:<br>
|
| 2415 |
+
For each fold in K-Fold CV:<br>
|
| 2416 |
+
Train KNN with this K value<br>
|
| 2417 |
+
Test on validation fold<br>
|
| 2418 |
+
Record accuracy<br>
|
| 2419 |
+
Calculate mean accuracy across all folds<br>
|
| 2420 |
+
Store: (K, mean_accuracy)<br>
|
| 2421 |
+
<br>
|
| 2422 |
+
Plot K vs Mean Accuracy<br>
|
| 2423 |
+
Choose K with highest mean accuracy
|
| 2424 |
+
</div>
|
| 2425 |
+
|
| 2426 |
+
<h3>Step-by-Step Process</h3>
|
| 2427 |
+
<ol>
|
| 2428 |
+
<li><strong>Define K Range:</strong> Try K = 1, 2, 3, ..., 20 (or use βn as starting point)</li>
|
| 2429 |
+
<li><strong>Set Up Cross-Validation:</strong> Use k-fold CV (e.g., k=10) to ensure robust evaluation</li>
|
| 2430 |
+
<li><strong>Train and Evaluate:</strong> For each K value, run k-fold CV, get accuracy for each fold, calculate mean Β± std dev</li>
|
| 2431 |
+
<li><strong>Select Optimal K:</strong> Choose K with highest mean accuracy (or use elbow method)</li>
|
| 2432 |
+
</ol>
|
| 2433 |
+
|
| 2434 |
+
<h3>Example Walkthrough</h3>
|
| 2435 |
+
<p><strong>Dataset:</strong> A, B, C, D, E, F (6 samples), k-fold = 3</p>
|
| 2436 |
+
|
| 2437 |
+
<table class="data-table">
|
| 2438 |
+
<thead>
|
| 2439 |
+
<tr><th>K Value</th><th>Fold 1</th><th>Fold 2</th><th>Fold 3</th><th>Mean Accuracy</th></tr>
|
| 2440 |
+
</thead>
|
| 2441 |
+
<tbody>
|
| 2442 |
+
<tr><td>K=1</td><td>100%</td><td>100%</td><td>50%</td><td>83.3%</td></tr>
|
| 2443 |
+
<tr style="background: rgba(126, 240, 212, 0.1);"><td><strong>K=3</strong></td><td>100%</td><td>100%</td><td>100%</td><td><strong>100% β Best!</strong></td></tr>
|
| 2444 |
+
<tr><td>K=5</td><td>100%</td><td>50%</td><td>100%</td><td>83.3%</td></tr>
|
| 2445 |
+
</tbody>
|
| 2446 |
+
</table>
|
| 2447 |
+
|
| 2448 |
+
<div class="figure">
|
| 2449 |
+
<div class="figure-placeholder" style="height: 400px">
|
| 2450 |
+
<canvas id="optimal-k-canvas"></canvas>
|
| 2451 |
+
</div>
|
| 2452 |
+
<p class="figure-caption"><strong>Figure:</strong> K vs Accuracy plot showing optimal K value</p>
|
| 2453 |
+
</div>
|
| 2454 |
+
|
| 2455 |
+
<div class="controls">
|
| 2456 |
+
<div class="control-group">
|
| 2457 |
+
<label>K Range (max): <span id="k-range-val">20</span></label>
|
| 2458 |
+
<input type="range" id="k-range-slider" min="10" max="30" step="5" value="20">
|
| 2459 |
+
</div>
|
| 2460 |
+
<div class="control-group">
|
| 2461 |
+
<label>CV Folds: <span id="cv-folds-val">10</span></label>
|
| 2462 |
+
<input type="range" id="cv-folds-slider" min="3" max="10" step="1" value="10">
|
| 2463 |
+
</div>
|
| 2464 |
+
</div>
|
| 2465 |
+
|
| 2466 |
+
<h3>Elbow Method</h3>
|
| 2467 |
+
<p>Look for the "elbow point" where accuracy stops improving significantly:</p>
|
| 2468 |
+
<ul>
|
| 2469 |
+
<li><strong>Sharp increase:</strong> Significant improvement with larger K</li>
|
| 2470 |
+
<li><strong>Elbow point:</strong> Diminishing returns begin</li>
|
| 2471 |
+
<li><strong>Plateau:</strong> Little benefit from larger K</li>
|
| 2472 |
+
<li><strong>Choose K at/near elbow:</strong> Best trade-off</li>
|
| 2473 |
+
</ul>
|
| 2474 |
+
|
| 2475 |
+
<div class="callout info">
|
| 2476 |
+
<div class="callout-title">π‘ Odd K Values</div>
|
| 2477 |
+
<div class="callout-content">
|
| 2478 |
+
Always prefer odd K values (3, 5, 7, 9) for binary classification! This avoids ties when neighbors vote. For K=4, you might get 2 votes for each class.
|
| 2479 |
+
</div>
|
| 2480 |
+
</div>
|
| 2481 |
+
|
| 2482 |
+
<div class="callout warning">
|
| 2483 |
+
<div class="callout-title">β οΈ Don't Use Test Set!</div>
|
| 2484 |
+
<div class="callout-content">
|
| 2485 |
+
Never use the test set for K selection! Always use cross-validation on training data only. The test set should remain untouched until final evaluation.
|
| 2486 |
+
</div>
|
| 2487 |
+
</div>
|
| 2488 |
+
|
| 2489 |
+
<h3>Practical Tips</h3>
|
| 2490 |
+
<ul>
|
| 2491 |
+
<li><strong>Start with K = βn:</strong> n = training samples (good starting point)</li>
|
| 2492 |
+
<li><strong>Use odd K:</strong> Avoids ties in binary classification</li>
|
| 2493 |
+
<li><strong>Consider computational cost:</strong> Large K = more neighbors to check</li>
|
| 2494 |
+
<li><strong>Visualize decision boundaries:</strong> For different K values</li>
|
| 2495 |
+
<li><strong>Use stratified k-fold:</strong> For imbalanced data</li>
|
| 2496 |
+
</ul>
|
| 2497 |
+
|
| 2498 |
+
<h3>Real-World Example</h3>
|
| 2499 |
+
<div class="info-card">
|
| 2500 |
+
<div class="info-card-title">πΈ Iris Flower Classification (150 samples)</div>
|
| 2501 |
+
<p style="margin: 12px 0; line-height: 1.6;">
|
| 2502 |
+
<strong>Process:</strong> Try K = 1 to 20, Use 10-fold CV<br>
|
| 2503 |
+
<strong>Results:</strong><br>
|
| 2504 |
+
β’ K=1: 95% accuracy (overfits to noise)<br>
|
| 2505 |
+
β’ K=7: 97% accuracy (optimal! β)<br>
|
| 2506 |
+
β’ K=15: 94% accuracy (underfits, too smooth)<br>
|
| 2507 |
+
<br>
|
| 2508 |
+
The optimal K=7 provides the best balance between model complexity and generalization!
|
| 2509 |
+
</p>
|
| 2510 |
+
</div>
|
| 2511 |
+
|
| 2512 |
+
<div class="callout success">
|
| 2513 |
+
<div class="callout-title">β
Key Takeaway</div>
|
| 2514 |
+
<div class="callout-content">
|
| 2515 |
+
Finding optimal K is not guesswork! Use systematic cross-validation to evaluate multiple K values and choose the one with highest mean accuracy. This ensures your KNN model generalizes well to unseen data.
|
| 2516 |
+
</div>
|
| 2517 |
+
</div>
|
| 2518 |
+
</div>
|
| 2519 |
+
</div>
|
| 2520 |
+
|
| 2521 |
+
<!-- Section 14: Hyperparameter Tuning & GridSearch -->
|
| 2522 |
+
<div class="section" id="hyperparameter-tuning">
|
| 2523 |
+
<div class="section-header">
|
| 2524 |
+
<h2>14. Hyperparameter Tuning & GridSearch βοΈ</h2>
|
| 2525 |
+
<button class="section-toggle">βΌ</button>
|
| 2526 |
+
</div>
|
| 2527 |
+
<div class="section-body">
|
| 2528 |
+
<p>Models have two types of parameters: <strong>learned parameters</strong> (like weights) and <strong>hyperparameters</strong> (like learning rate). We must tune hyperparameters to get the best model!</p>
|
| 2529 |
+
|
| 2530 |
+
<h3>What Are Hyperparameters?</h3>
|
| 2531 |
+
<p><strong>Definition:</strong> Parameters that control the learning process but aren't learned from data.</p>
|
| 2532 |
+
|
| 2533 |
+
<div class="info-card">
|
| 2534 |
+
<div class="info-card-title">Parameters vs Hyperparameters</div>
|
| 2535 |
+
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-top: 12px;">
|
| 2536 |
+
<div style="background: rgba(126, 240, 212, 0.1); padding: 12px; border-radius: 6px;">
|
| 2537 |
+
<strong style="color: #7ef0d4;">Parameters (Learned)</strong>
|
| 2538 |
+
<ul style="margin-top: 8px; font-size: 14px;">
|
| 2539 |
+
<li>Linear Regression: w, b</li>
|
| 2540 |
+
<li>Logistic Regression: coefficients</li>
|
| 2541 |
+
<li>SVM: support vector positions</li>
|
| 2542 |
+
<li>Optimized during training</li>
|
| 2543 |
+
</ul>
|
| 2544 |
+
</div>
|
| 2545 |
+
<div style="background: rgba(106, 169, 255, 0.1); padding: 12px; border-radius: 6px;">
|
| 2546 |
+
<strong style="color: #6aa9ff;">Hyperparameters (Set Before)</strong>
|
| 2547 |
+
<ul style="margin-top: 8px; font-size: 14px;">
|
| 2548 |
+
<li>Learning rate (Ξ±)</li>
|
| 2549 |
+
<li>Number of iterations</li>
|
| 2550 |
+
<li>SVM: C, gamma, kernel</li>
|
| 2551 |
+
<li>KNN: K value</li>
|
| 2552 |
+
<li>Must be tuned manually</li>
|
| 2553 |
+
</ul>
|
| 2554 |
+
</div>
|
| 2555 |
+
</div>
|
| 2556 |
+
</div>
|
| 2557 |
+
|
| 2558 |
+
<h3>Examples Across Algorithms</h3>
|
| 2559 |
+
|
| 2560 |
+
<h4>Linear/Logistic Regression:</h4>
|
| 2561 |
+
<ul>
|
| 2562 |
+
<li><strong>Learning rate (Ξ±):</strong> 0.001, 0.01, 0.1</li>
|
| 2563 |
+
<li><strong>Number of iterations:</strong> 100, 1000, 10000</li>
|
| 2564 |
+
<li><strong>Regularization strength (Ξ»):</strong> 0.01, 0.1, 1, 10</li>
|
| 2565 |
+
</ul>
|
| 2566 |
+
|
| 2567 |
+
<h4>SVM:</h4>
|
| 2568 |
+
<ul>
|
| 2569 |
+
<li><strong>C (regularization):</strong> 0.1, 1, 10, 100, 1000</li>
|
| 2570 |
+
<li><strong>gamma (kernel coefficient):</strong> 'scale', 'auto', 0.001, 0.01, 0.1</li>
|
| 2571 |
+
<li><strong>kernel:</strong> 'linear', 'poly', 'rbf', 'sigmoid'</li>
|
| 2572 |
+
<li><strong>degree (for poly):</strong> 2, 3, 4, 5</li>
|
| 2573 |
+
</ul>
|
| 2574 |
+
|
| 2575 |
+
<h4>KNN:</h4>
|
| 2576 |
+
<ul>
|
| 2577 |
+
<li><strong>K (neighbors):</strong> 1, 3, 5, 7, 9, 11</li>
|
| 2578 |
+
<li><strong>Distance metric:</strong> 'euclidean', 'manhattan', 'minkowski'</li>
|
| 2579 |
+
<li><strong>Weights:</strong> 'uniform', 'distance'</li>
|
| 2580 |
+
</ul>
|
| 2581 |
+
|
| 2582 |
+
<div class="callout warning">
|
| 2583 |
+
<div class="callout-title">β οΈ The Problem with Random Values</div>
|
| 2584 |
+
<div class="callout-content">
|
| 2585 |
+
If we just try random hyperparameter values:<br>
|
| 2586 |
+
β’ Inefficient (might miss optimal combination)<br>
|
| 2587 |
+
β’ No systematic approach<br>
|
| 2588 |
+
β’ Hard to reproduce<br>
|
| 2589 |
+
β’ Wastes time and resources
|
| 2590 |
+
</div>
|
| 2591 |
+
</div>
|
| 2592 |
+
|
| 2593 |
+
<h3>Solution: GridSearch!</h3>
|
| 2594 |
+
<p><strong>What is GridSearch?</strong> Systematically try all combinations of hyperparameters and pick the best.</p>
|
| 2595 |
+
|
| 2596 |
+
<div class="formula">
|
| 2597 |
+
<strong>GridSearch Algorithm:</strong><br>
|
| 2598 |
+
1. Define parameter grid:<br>
|
| 2599 |
+
{ 'C': [0.1, 1, 10, 100],<br>
|
| 2600 |
+
'gamma': ['scale', 'auto', 0.001, 0.01],<br>
|
| 2601 |
+
'kernel': ['linear', 'rbf', 'poly'] }<br>
|
| 2602 |
+
<br>
|
| 2603 |
+
2. Generate all combinations:<br>
|
| 2604 |
+
Total: 4 Γ 4 Γ 3 = 48 combinations<br>
|
| 2605 |
+
<br>
|
| 2606 |
+
3. For each combination:<br>
|
| 2607 |
+
- Train model with these hyperparameters<br>
|
| 2608 |
+
- Evaluate using cross-validation<br>
|
| 2609 |
+
- Record mean CV score<br>
|
| 2610 |
+
<br>
|
| 2611 |
+
4. Select best combination:<br>
|
| 2612 |
+
- Highest CV score = best hyperparameters
|
| 2613 |
+
</div>
|
| 2614 |
+
|
| 2615 |
+
<div class="figure">
|
| 2616 |
+
<div class="figure-placeholder" style="height: 400px">
|
| 2617 |
+
<canvas id="gridsearch-canvas"></canvas>
|
| 2618 |
+
</div>
|
| 2619 |
+
<p class="figure-caption"><strong>Figure:</strong> GridSearch heatmap showing parameter combinations and their scores</p>
|
| 2620 |
+
</div>
|
| 2621 |
+
|
| 2622 |
+
<h3>SVM GridSearch Example</h3>
|
| 2623 |
+
|
| 2624 |
+
<table class="data-table">
|
| 2625 |
+
<thead>
|
| 2626 |
+
<tr><th>#</th><th>C</th><th>gamma</th><th>kernel</th><th>CV Score</th></tr>
|
| 2627 |
+
</thead>
|
| 2628 |
+
<tbody>
|
| 2629 |
+
<tr><td>1</td><td>0.1</td><td>0.001</td><td>linear</td><td>0.85</td></tr>
|
| 2630 |
+
<tr><td>2</td><td>0.1</td><td>0.001</td><td>rbf</td><td>0.88</td></tr>
|
| 2631 |
+
<tr><td>...</td><td>...</td><td>...</td><td>...</td><td>...</td></tr>
|
| 2632 |
+
<tr style="background: rgba(126, 240, 212, 0.1);"><td><strong>32</strong></td><td><strong>10</strong></td><td><strong>0.01</strong></td><td><strong>rbf</strong></td><td><strong>0.95 β Best!</strong></td></tr>
|
| 2633 |
+
</tbody>
|
| 2634 |
+
</table>
|
| 2635 |
+
|
| 2636 |
+
<p><strong>Result:</strong> Best parameters found automatically: C=10, gamma=0.01, kernel='rbf'</p>
|
| 2637 |
+
|
| 2638 |
+
<h3>Computational Cost</h3>
|
| 2639 |
+
<div class="formula">
|
| 2640 |
+
<strong>Total Time Formula:</strong><br>
|
| 2641 |
+
Total Time = n_combinations Γ cv_folds Γ training_time<br>
|
| 2642 |
+
<br>
|
| 2643 |
+
<strong>Example:</strong><br>
|
| 2644 |
+
β’ 48 combinations<br>
|
| 2645 |
+
β’ 5-fold CV<br>
|
| 2646 |
+
β’ 1 second per training<br>
|
| 2647 |
+
<strong>Total:</strong> 48 Γ 5 Γ 1 = 240 seconds (4 minutes)
|
| 2648 |
+
</div>
|
| 2649 |
+
|
| 2650 |
+
<div class="callout warning">
|
| 2651 |
+
<div class="callout-title">β οΈ GridSearch Can Be Slow!</div>
|
| 2652 |
+
<div class="callout-content">
|
| 2653 |
+
For large parameter grids, GridSearch can take hours or days! Solutions:<br>
|
| 2654 |
+
β’ Use fewer parameter values (coarse then fine grid)<br>
|
| 2655 |
+
β’ Use RandomizedSearchCV (samples random combinations)<br>
|
| 2656 |
+
β’ Use parallel processing (n_jobs=-1)
|
| 2657 |
+
</div>
|
| 2658 |
+
</div>
|
| 2659 |
+
|
| 2660 |
+
<div class="callout info">
|
| 2661 |
+
<div class="callout-title">π‘ Always Use Cross-Validation!</div>
|
| 2662 |
+
<div class="callout-content">
|
| 2663 |
+
GridSearch must use cross-validation internally to avoid overfitting to validation set. Never tune hyperparameters on test set!
|
| 2664 |
+
</div>
|
| 2665 |
+
</div>
|
| 2666 |
+
|
| 2667 |
+
<h3>Practical Workflow</h3>
|
| 2668 |
+
<ol>
|
| 2669 |
+
<li><strong>Step 1 - Coarse Grid:</strong> Wide range, few values (e.g., C = [0.1, 1, 10, 100, 1000]) to find approximate best region</li>
|
| 2670 |
+
<li><strong>Step 2 - Fine Grid:</strong> Narrow range, more values (e.g., C = [5, 7, 9, 11, 13]) to refine optimal value</li>
|
| 2671 |
+
<li><strong>Step 3 - Final Model:</strong> Train on full training set using best hyperparameters, then evaluate on test set</li>
|
| 2672 |
+
</ol>
|
| 2673 |
+
|
| 2674 |
+
<div class="callout success">
|
| 2675 |
+
<div class="callout-title">β
Key Takeaway</div>
|
| 2676 |
+
<div class="callout-content">
|
| 2677 |
+
GridSearch finds optimal hyperparameters automatically - no manual guessing needed! It's the standard approach for hyperparameter tuning in machine learning. Just be patient with large grids!
|
| 2678 |
+
</div>
|
| 2679 |
+
</div>
|
| 2680 |
+
|
| 2681 |
+
<h3>Advanced: RandomizedSearchCV</h3>
|
| 2682 |
+
<p>For very large hyperparameter spaces, use <strong>RandomizedSearchCV</strong>:</p>
|
| 2683 |
+
<ul>
|
| 2684 |
+
<li>Samples random combinations instead of trying all</li>
|
| 2685 |
+
<li>Much faster than exhaustive GridSearch</li>
|
| 2686 |
+
<li>Good for many hyperparameters or continuous ranges</li>
|
| 2687 |
+
<li>Specify number of iterations (e.g., 100 random combinations)</li>
|
| 2688 |
+
</ul>
|
| 2689 |
+
</div>
|
| 2690 |
+
</div>
|
| 2691 |
+
|
| 2692 |
+
<!-- Section 15: Naive Bayes Classifier -->
|
| 2693 |
+
<div class="section" id="naive-bayes">
|
| 2694 |
+
<div class="section-header">
|
| 2695 |
+
<h2>15. Naive Bayes Classifier π</h2>
|
| 2696 |
+
<button class="section-toggle">βΌ</button>
|
| 2697 |
+
</div>
|
| 2698 |
+
<div class="section-body">
|
| 2699 |
+
<p>Naive Bayes is a probabilistic classifier based on Bayes' Theorem. It's called "naive" because it assumes features are independent (which often isn't true, but it works surprisingly well anyway!)</p>
|
| 2700 |
+
|
| 2701 |
+
<div class="info-card">
|
| 2702 |
+
<div class="info-card-title">Key Concepts</div>
|
| 2703 |
+
<ul class="info-card-list">
|
| 2704 |
+
<li>Based on Bayes' Theorem and probability</li>
|
| 2705 |
+
<li>Assumes features are independent ("naive" assumption)</li>
|
| 2706 |
+
<li>Fast training and prediction</li>
|
| 2707 |
+
<li>Works well for text classification</li>
|
| 2708 |
+
</ul>
|
| 2709 |
+
</div>
|
| 2710 |
+
|
| 2711 |
+
<h3>Bayes' Theorem</h3>
|
| 2712 |
+
<div class="formula">
|
| 2713 |
+
<strong>Bayes' Theorem:</strong><br>
|
| 2714 |
+
P(A|B) = P(B|A) Γ P(A) / P(B)<br>
|
| 2715 |
+
<br>
|
| 2716 |
+
<strong>In classification context:</strong><br>
|
| 2717 |
+
P(class|features) = P(features|class) Γ P(class) / P(features)<br>
|
| 2718 |
+
<br>
|
| 2719 |
+
<small>where:<br>
|
| 2720 |
+
β’ P(class|features) = Posterior probability (what we want)<br>
|
| 2721 |
+
β’ P(features|class) = Likelihood<br>
|
| 2722 |
+
β’ P(class) = Prior probability<br>
|
| 2723 |
+
β’ P(features) = Evidence (normalizing constant)</small>
|
| 2724 |
+
</div>
|
| 2725 |
+
|
| 2726 |
+
<h3>Simple Example: Email Spam Classification</h3>
|
| 2727 |
+
<p>Email contains words: ["free", "money"]</p>
|
| 2728 |
+
<p><strong>Calculate:</strong> P(spam|free, money)</p>
|
| 2729 |
+
|
| 2730 |
+
<h4>Given:</h4>
|
| 2731 |
+
<ul>
|
| 2732 |
+
<li>P(spam) = 0.3 (30% emails are spam)</li>
|
| 2733 |
+
<li>P(not spam) = 0.7</li>
|
| 2734 |
+
<li>P(free|spam) = 0.8</li>
|
| 2735 |
+
<li>P(money|spam) = 0.7</li>
|
| 2736 |
+
<li>P(free|not spam) = 0.1</li>
|
| 2737 |
+
<li>P(money|not spam) = 0.05</li>
|
| 2738 |
+
</ul>
|
| 2739 |
+
|
| 2740 |
+
<h4>Naive Assumption (features are independent):</h4>
|
| 2741 |
+
<div class="formula">
|
| 2742 |
+
P(free, money|spam) = P(free|spam) Γ P(money|spam)<br>
|
| 2743 |
+
= 0.8 Γ 0.7 = 0.56<br>
|
| 2744 |
+
<br>
|
| 2745 |
+
P(free, money|not spam) = 0.1 Γ 0.05 = 0.005
|
| 2746 |
+
</div>
|
| 2747 |
+
|
| 2748 |
+
<h4>Calculate Posterior:</h4>
|
| 2749 |
+
<div class="formula">
|
| 2750 |
+
P(spam|features) = P(free, money|spam) Γ P(spam)<br>
|
| 2751 |
+
= 0.56 Γ 0.3 = 0.168<br>
|
| 2752 |
+
<br>
|
| 2753 |
+
P(not spam|features) = 0.005 Γ 0.7 = 0.0035<br>
|
| 2754 |
+
<br>
|
| 2755 |
+
<strong>Normalize:</strong><br>
|
| 2756 |
+
P(spam|features) = 0.168 / (0.168 + 0.0035) = 0.98<br>
|
| 2757 |
+
<br>
|
| 2758 |
+
<strong style="color: #7ef0d4;">Result: 98% probability it's spam! π§</strong>
|
| 2759 |
+
</div>
|
| 2760 |
+
|
| 2761 |
+
<div class="figure">
|
| 2762 |
+
<div class="figure-placeholder" style="height: 350px">
|
| 2763 |
+
<canvas id="naive-bayes-canvas"></canvas>
|
| 2764 |
+
</div>
|
| 2765 |
+
<p class="figure-caption"><strong>Figure:</strong> Naive Bayes probability calculations for spam detection</p>
|
| 2766 |
+
</div>
|
| 2767 |
+
|
| 2768 |
+
<h3>Types of Naive Bayes</h3>
|
| 2769 |
+
|
| 2770 |
+
<h4>1. Gaussian Naive Bayes</h4>
|
| 2771 |
+
<ul>
|
| 2772 |
+
<li><strong>For:</strong> Continuous features</li>
|
| 2773 |
+
<li><strong>Assumes:</strong> Normal distribution</li>
|
| 2774 |
+
<li><strong>Formula:</strong> P(x|class) = (1/β(2ΟΟΒ²)) Γ e^(-(x-ΞΌ)Β²/(2ΟΒ²))</li>
|
| 2775 |
+
<li><strong>Use case:</strong> Real-valued features (height, weight, temperature)</li>
|
| 2776 |
+
</ul>
|
| 2777 |
+
|
| 2778 |
+
<h4>2. Multinomial Naive Bayes</h4>
|
| 2779 |
+
<ul>
|
| 2780 |
+
<li><strong>For:</strong> Count data</li>
|
| 2781 |
+
<li><strong>Features:</strong> Frequencies (e.g., word counts)</li>
|
| 2782 |
+
<li><strong>Use case:</strong> Text classification (word counts in documents)</li>
|
| 2783 |
+
</ul>
|
| 2784 |
+
|
| 2785 |
+
<h4>3. Bernoulli Naive Bayes</h4>
|
| 2786 |
+
<ul>
|
| 2787 |
+
<li><strong>For:</strong> Binary features (0/1, yes/no)</li>
|
| 2788 |
+
<li><strong>Features:</strong> Presence/absence</li>
|
| 2789 |
+
<li><strong>Use case:</strong> Document classification (word present or not)</li>
|
| 2790 |
+
</ul>
|
| 2791 |
+
|
| 2792 |
+
<h3>Training Algorithm</h3>
|
| 2793 |
+
<div class="formula">
|
| 2794 |
+
<strong>Training Process:</strong><br>
|
| 2795 |
+
For each class:<br>
|
| 2796 |
+
Calculate P(class) = count(class) / total_samples<br>
|
| 2797 |
+
<br>
|
| 2798 |
+
For each feature:<br>
|
| 2799 |
+
Calculate P(feature|class)<br>
|
| 2800 |
+
<br>
|
| 2801 |
+
Gaussian: Estimate ΞΌ and Ο<br>
|
| 2802 |
+
Multinomial: Count frequencies<br>
|
| 2803 |
+
Bernoulli: Count presence<br>
|
| 2804 |
+
<br>
|
| 2805 |
+
<strong>Prediction Process:</strong><br>
|
| 2806 |
+
For each class:<br>
|
| 2807 |
+
posterior = P(class) Γ β P(feature_i|class)<br>
|
| 2808 |
+
<br>
|
| 2809 |
+
Choose class with maximum posterior
|
| 2810 |
+
</div>
|
| 2811 |
+
|
| 2812 |
+
<h3>Worked Example: Play Tennis Dataset</h3>
|
| 2813 |
+
<p>Predict: Should we play tennis?</p>
|
| 2814 |
+
<p><strong>Given:</strong> Sunny, Cool, High humidity, Windy</p>
|
| 2815 |
+
|
| 2816 |
+
<table class="data-table">
|
| 2817 |
+
<thead>
|
| 2818 |
+
<tr><th>Outlook</th><th>Temp</th><th>Humidity</th><th>Windy</th><th>Play</th></tr>
|
| 2819 |
+
</thead>
|
| 2820 |
+
<tbody>
|
| 2821 |
+
<tr><td>Sunny</td><td>Hot</td><td>High</td><td>No</td><td>No</td></tr>
|
| 2822 |
+
<tr><td>Sunny</td><td>Hot</td><td>High</td><td>Yes</td><td>No</td></tr>
|
| 2823 |
+
<tr><td>Overcast</td><td>Hot</td><td>High</td><td>No</td><td>Yes</td></tr>
|
| 2824 |
+
<tr><td>Rain</td><td>Mild</td><td>High</td><td>No</td><td>Yes</td></tr>
|
| 2825 |
+
<tr><td>Rain</td><td>Cool</td><td>Normal</td><td>No</td><td>Yes</td></tr>
|
| 2826 |
+
<tr><td>...</td><td>...</td><td>...</td><td>...</td><td>...</td></tr>
|
| 2827 |
+
</tbody>
|
| 2828 |
+
</table>
|
| 2829 |
+
|
| 2830 |
+
<p>Calculate P(Yes|features) and P(No|features), then compare!</p>
|
| 2831 |
+
|
| 2832 |
+
<h3>Advantages</h3>
|
| 2833 |
+
<ul>
|
| 2834 |
+
<li>β <strong>Fast training and prediction:</strong> Very efficient</li>
|
| 2835 |
+
<li>β <strong>Works well with high dimensions:</strong> Many features</li>
|
| 2836 |
+
<li>β <strong>Requires small training data:</strong> Good for limited data</li>
|
| 2837 |
+
<li>β <strong>Handles missing values well:</strong> Robust</li>
|
| 2838 |
+
<li>β <strong>Probabilistic predictions:</strong> Returns confidence scores</li>
|
| 2839 |
+
<li>β <strong>Good baseline classifier:</strong> Easy to implement</li>
|
| 2840 |
+
</ul>
|
| 2841 |
+
|
| 2842 |
+
<h3>Disadvantages</h3>
|
| 2843 |
+
<ul>
|
| 2844 |
+
<li>β <strong>Independence assumption often wrong:</strong> Features are usually correlated</li>
|
| 2845 |
+
<li>β <strong>Zero probability problem:</strong> Needs Laplace smoothing</li>
|
| 2846 |
+
<li>β <strong>Not great for correlated features:</strong> Performance suffers</li>
|
| 2847 |
+
<li>β <strong>Requires distribution assumption:</strong> For continuous features</li>
|
| 2848 |
+
</ul>
|
| 2849 |
+
|
| 2850 |
+
<div class="callout info">
|
| 2851 |
+
<div class="callout-title">π‘ Despite "Naive" Assumption</div>
|
| 2852 |
+
<div class="callout-content">
|
| 2853 |
+
Despite the naive independence assumption being violated in most real-world datasets, Naive Bayes often works remarkably well in practice! It's especially powerful for text classification tasks.
|
| 2854 |
+
</div>
|
| 2855 |
+
</div>
|
| 2856 |
+
|
| 2857 |
+
<div class="callout warning">
|
| 2858 |
+
<div class="callout-title">β οΈ Zero Probability Problem</div>
|
| 2859 |
+
<div class="callout-content">
|
| 2860 |
+
If a feature value never occurs with a class in training, P = 0! This makes the entire posterior zero.<br>
|
| 2861 |
+
<br>
|
| 2862 |
+
<strong>Solution: Laplace Smoothing</strong><br>
|
| 2863 |
+
P(feature|class) = (count + Ξ±) / (total + Ξ± Γ n_features)<br>
|
| 2864 |
+
where Ξ± = smoothing parameter (usually 1)
|
| 2865 |
+
</div>
|
| 2866 |
+
</div>
|
| 2867 |
+
|
| 2868 |
+
<h3>Applications</h3>
|
| 2869 |
+
<ul>
|
| 2870 |
+
<li><strong>Spam filtering:</strong> Email classification (spam/not spam)</li>
|
| 2871 |
+
<li><strong>Sentiment analysis:</strong> Positive/negative reviews</li>
|
| 2872 |
+
<li><strong>Document classification:</strong> Topic categorization</li>
|
| 2873 |
+
<li><strong>Medical diagnosis:</strong> Disease prediction from symptoms</li>
|
| 2874 |
+
<li><strong>Real-time prediction:</strong> Fast classification needed</li>
|
| 2875 |
+
<li><strong>Recommendation systems:</strong> User preferences</li>
|
| 2876 |
+
</ul>
|
| 2877 |
+
|
| 2878 |
+
<div class="callout success">
|
| 2879 |
+
<div class="callout-title">β
Key Takeaway</div>
|
| 2880 |
+
<div class="callout-content">
|
| 2881 |
+
Naive Bayes is simple, fast, and surprisingly effective! Despite its "naive" independence assumption, it's a powerful baseline classifier that works especially well for text classification. Great for when you need quick results with limited data!
|
| 2882 |
+
</div>
|
| 2883 |
+
</div>
|
| 2884 |
+
|
| 2885 |
+
<h3>π Congratulations!</h3>
|
| 2886 |
+
<p style="font-size: 18px; color: #7ef0d4; margin-top: 24px;">
|
| 2887 |
+
You've now completed all 15 machine learning topics! From basic concepts to advanced techniques, you've learned linear regression, gradient descent, classification algorithms, model evaluation, regularization, hyperparameter tuning, and probabilistic methods. You're ready to build real ML projects! π
|
| 2888 |
+
</p>
|
| 2889 |
+
</div>
|
| 2890 |
+
</div>
|
| 2891 |
+
|
| 2892 |
</main>
|
| 2893 |
</div>
|
| 2894 |
|