Download Static/js/linear.js from deedrop1140/machinelearningalgorithms: direct link, hf CLI and curl.
- Browser
- Download file 10.6 kB
-
https://huggingface.co/spaces/deedrop1140/machinelearningalgorithms/resolve/main/Static/js/linear.js
- Command line
-
hf download hf://spaces/deedrop1140/machinelearningalgorithms/Static/js/linear.js
-
curl -L -o linear.js https://huggingface.co/spaces/deedrop1140/machinelearningalgorithms/resolve/main/Static/js/linear.js
10.6 kB
| // Get canvas and context | |
| const canvas = document.getElementById('regressionCanvas'); | |
| const ctx = canvas.getContext('2d'); | |
| // Data from your Python script (X, y) | |
| // These are hardcoded here for visualization purposes. | |
| // In a real advanced app, these might be dynamically loaded. | |
| const X_data = [1, 2, 3, 4, 5]; | |
| const y_data = [35, 45, 55, 65, 75]; | |
| // --- Understanding Slope (m) and Intercept (b) --- | |
| // For a perfect linear relationship as in your data, | |
| // we can manually calculate slope (m) and intercept (b). | |
| // In a real-world scenario with scattered data, the scikit-learn | |
| // LinearRegression model uses more advanced statistical methods | |
| // (like Ordinary Least Squares) to find the 'best fit' line | |
| // that minimizes the squared differences between actual and predicted y values. | |
| // Calculate Slope (m): | |
| // m = (y2 - y1) / (x2 - x1) | |
| // Using points (1, 35) and (2, 45): | |
| // m = (45 - 35) / (2 - 1) = 10 / 1 = 10 | |
| const slope = 10; | |
| // Calculate Intercept (b): | |
| // b = y - m * x | |
| // Using point (1, 35) and calculated slope m=10: | |
| // b = 35 - (10 * 1) = 35 - 10 = 25 | |
| const intercept = 25; | |
| // Display slope and intercept values in the HTML | |
| document.getElementById('slopeValue').textContent = slope.toFixed(2); | |
| document.getElementById('interceptValue').textContent = intercept.toFixed(2); | |
| // Canvas dimensions and padding | |
| let canvasWidth, canvasHeight; | |
| const padding = 50; | |
| // Scale factors for drawing data onto the canvas | |
| let xScale, yScale; | |
| let xMin, xMax, yMin, yMax; | |
| // Prediction variables (these will be updated when the user inputs hours) | |
| let predictedHours = null; | |
| let predictedScore = null; | |
| // Function to set up scaling based on data range and canvas size | |
| function setupScaling() { | |
| canvasWidth = canvas.width; | |
| canvasHeight = canvas.height; | |
| // Determine data ranges for X and Y axes | |
| xMin = Math.min(...X_data, 0); // Always start X-axis at 0 | |
| // Set xMax to at least 10 (as per the last request) and ensure it covers any new predicted hours | |
| xMax = Math.max(...X_data, predictedHours !== null ? predictedHours : 0, 10) + 1; // Extend x-axis slightly beyond 10 | |
| yMin = Math.min(...y_data, 0); // Always start Y-axis at 0 | |
| // Calculate the predicted score for the determined xMax to ensure the y-axis covers the line | |
| const maxPredictedY = slope * xMax + intercept; | |
| yMax = Math.max(...y_data, predictedScore !== null ? predictedScore : 0, maxPredictedY) + 20; // Extend y-axis slightly beyond max needed | |
| // Calculate scaling factors to fit data within the canvas padding | |
| xScale = (canvasWidth - 2 * padding) / (xMax - xMin); | |
| yScale = (canvasHeight - 2 * padding) / (yMax - yMin); | |
| } | |
| // Convert data coordinates (e.g., hours, score) to canvas pixel coordinates | |
| function toCanvasX(x) { | |
| return padding + (x - xMin) * xScale; | |
| } | |
| function toCanvasY(y) { | |
| return canvasHeight - padding - (y - yMin) * yScale; | |
| } | |
| // Function to draw the entire graph, including data points, regression line, and predictions | |
| function drawGraph() { | |
| ctx.clearRect(0, 0, canvasWidth, canvasHeight); // Clear the entire canvas | |
| // Draw axes | |
| ctx.beginPath(); | |
| ctx.strokeStyle = '#64748b'; // Slate gray for axes | |
| ctx.lineWidth = 2; | |
| // X-axis (horizontal line) | |
| ctx.moveTo(padding, toCanvasY(yMin)); | |
| ctx.lineTo(canvasWidth - padding, toCanvasY(yMin)); | |
| // Y-axis (vertical line) | |
| ctx.moveTo(toCanvasX(xMin), padding); | |
| ctx.lineTo(toCanvasX(xMin), canvasHeight - padding); | |
| ctx.stroke(); | |
| // Draw axis labels and ticks | |
| ctx.fillStyle = '#475569'; // Darker gray for labels | |
| ctx.font = '14px Inter'; | |
| ctx.textAlign = 'center'; | |
| ctx.textBaseline = 'top'; | |
| // X-axis labels (Hours Studied) | |
| // Dynamic tick step for clarity on different scales | |
| const xTickStep = 1; // Every 1 hour for a graph up to 10 | |
| for (let i = Math.ceil(xMin / xTickStep) * xTickStep; i <= Math.floor(xMax); i += xTickStep) { | |
| if (i >= 0) { | |
| ctx.fillText(i + 'h', toCanvasX(i), canvasHeight - padding + 10); | |
| ctx.beginPath(); | |
| ctx.moveTo(toCanvasX(i), canvasHeight - padding); | |
| ctx.lineTo(toCanvasX(i), canvasHeight - padding - 5); | |
| ctx.stroke(); | |
| } | |
| } | |
| // X-axis title | |
| ctx.fillText('Hours Studied', canvasWidth / 2, canvasHeight - 20); | |
| ctx.textAlign = 'right'; | |
| ctx.textBaseline = 'middle'; | |
| // Y-axis labels (Score) | |
| // Dynamic tick step for clarity on different scales | |
| const yTickStep = (yMax - yMin) / 10 > 20 ? 50 : 20; // Example: every 20 or 50 points | |
| for (let i = Math.ceil(yMin / yTickStep) * yTickStep; i <= Math.floor(yMax); i += yTickStep) { | |
| if (i >= 0) { | |
| ctx.fillText(i.toFixed(0), padding - 10, toCanvasY(i)); | |
| ctx.beginPath(); | |
| ctx.moveTo(padding, toCanvasY(i)); | |
| ctx.lineTo(padding + 5, toCanvasY(i)); | |
| ctx.stroke(); | |
| } | |
| } | |
| // Y-axis title (rotated) | |
| ctx.save(); | |
| ctx.translate(20, canvasHeight / 2); | |
| ctx.rotate(-Math.PI / 2); | |
| ctx.textAlign = 'center'; | |
| ctx.fillText('Score', 0, 0); | |
| ctx.restore(); | |
| // Draw data points (blue circles) | |
| ctx.fillStyle = '#3b82f6'; // Blue for data points | |
| X_data.forEach((x, i) => { | |
| ctx.beginPath(); | |
| ctx.arc(toCanvasX(x), toCanvasY(y_data[i]), 5, 0, Math.PI * 2); // Radius 5 | |
| ctx.fill(); | |
| }); | |
| // Draw regression line (red line) | |
| ctx.beginPath(); | |
| ctx.strokeStyle = '#ef4444'; // Red for regression line | |
| ctx.lineWidth = 3; | |
| // Draw line across the entire X-axis range based on the model equation | |
| ctx.moveTo(toCanvasX(xMin), toCanvasY(slope * xMin + intercept)); | |
| ctx.lineTo(toCanvasX(xMax), toCanvasY(slope * xMax + intercept)); | |
| ctx.stroke(); | |
| // Draw predicted point and lines if available (green point and dashed lines) | |
| if (predictedHours !== null && predictedScore !== null) { | |
| const predX = toCanvasX(predictedHours); | |
| const predY = toCanvasY(predictedScore); | |
| // Predicted point | |
| ctx.fillStyle = '#22c55e'; // Green for predicted point | |
| ctx.beginPath(); | |
| ctx.arc(predX, predY, 6, 0, Math.PI * 2); // Slightly larger radius | |
| ctx.fill(); | |
| // Dotted lines to axes | |
| ctx.strokeStyle = '#22c55e'; // Green for dotted lines | |
| ctx.lineWidth = 1.5; | |
| ctx.setLineDash([5, 5]); // Dotted line style | |
| // Line from predicted point to X-axis | |
| ctx.beginPath(); | |
| ctx.moveTo(predX, predY); | |
| ctx.lineTo(predX, toCanvasY(yMin)); | |
| ctx.stroke(); | |
| // Line from predicted point to Y-axis | |
| ctx.beginPath(); | |
| ctx.moveTo(predX, predY); | |
| ctx.lineTo(toCanvasX(xMin), predY); | |
| ctx.stroke(); | |
| ctx.setLineDash([]); // Reset line dash to solid for subsequent drawings | |
| } | |
| } | |
| // Event listener for the "Predict Score" button click | |
| document.getElementById('predictBtn').addEventListener('click', () => { | |
| // Get the value from the input field and parse it as a floating-point number | |
| const hoursInput = parseFloat(document.getElementById('hoursInput').value); | |
| // Check if the input is a valid number | |
| if (!isNaN(hoursInput)) { | |
| // Update global prediction variables | |
| predictedHours = hoursInput; | |
| predictedScore = slope * predictedHours + intercept; | |
| // Display the predicted score in the HTML | |
| document.getElementById('predictedScore').textContent = predictedScore.toFixed(2); | |
| // Make the prediction output box visible | |
| document.getElementById('predictionOutput').classList.remove('hidden'); | |
| // Recalculate scaling and redraw the graph to accommodate new prediction if it extends axes | |
| setupScaling(); | |
| drawGraph(); | |
| } else { | |
| // If input is invalid, display an error message | |
| const outputDiv = document.getElementById('predictionOutput'); | |
| outputDiv.innerHTML = '<p class="text-red-600">Please enter a valid number for hours studied.</p>'; | |
| outputDiv.classList.remove('hidden'); | |
| } | |
| }); | |
| // Function to handle canvas resizing and redraw the graph | |
| function resizeCanvas() { | |
| // Get the device pixel ratio for sharper rendering on high-DPI screens | |
| const dpi = window.devicePixelRatio; | |
| // Get the actual rendered size of the canvas element from its CSS styles | |
| const rect = canvas.getBoundingClientRect(); | |
| // Set the internal drawing buffer size of the canvas | |
| canvas.width = rect.width * dpi; | |
| canvas.height = rect.height * dpi; | |
| // Scale the drawing context to match the DPI, ensuring crisp lines and text | |
| ctx.scale(dpi, dpi); | |
| // Re-setup scaling for data to canvas coordinates and redraw | |
| setupScaling(); | |
| drawGraph(); | |
| } | |
| // Initial setup and draw when the window loads | |
| window.addEventListener('load', () => { | |
| resizeCanvas(); // Set initial canvas size and draw | |
| // Also trigger an initial prediction for the default value in the input field | |
| const initialHours = parseFloat(document.getElementById('hoursInput').value); | |
| if (!isNaN(initialHours)) { | |
| predictedHours = initialHours; | |
| predictedScore = slope * initialHours + intercept; | |
| document.getElementById('predictedScore').textContent = predictedScore.toFixed(2); | |
| document.getElementById('predictionOutput').classList.remove('hidden'); | |
| setupScaling(); | |
| drawGraph(); | |
| } | |
| }); | |
| // Redraw the graph whenever the window is resized | |
| window.addEventListener('resize', resizeCanvas); | |
| // Optional: Allow clicking on canvas to set hours input (for quick testing) | |
| canvas.addEventListener('click', (event) => { | |
| // Get mouse click coordinates relative to the canvas | |
| const rect = canvas.getBoundingClientRect(); | |
| const mouseX = (event.clientX - rect.left) / (canvas.width / canvas.getBoundingClientRect().width); | |
| const mouseY = (event.clientY - rect.top) / (canvas.height / canvas.getBoundingClientRect().height); // Corrected this line | |
| // Convert canvas X coordinate back to data X (hours studied) | |
| const clickedHours = xMin + (mouseX - padding) / xScale; | |
| // Update the input field with the clicked hours | |
| document.getElementById('hoursInput').value = clickedHours.toFixed(1); | |
| // Trigger the prediction immediately | |
| document.getElementById('predictBtn').click(); | |
| }); | |