--- title: "Data Science Methods for Forecasting in Energy and Economics" date: 2025-07-10 format: revealjs: embed-resources: true footer: "" execute: daemon: false highlight-style: github --- ## B-spline Basis Functions ```{ojs} d3 = require("d3@7") ``` ```{ojs} bsplineData = FileAttachment("basis_functions.csv").csv({ typed: true }) knotValues = Array.from(new Set(bsplineData.map(d => d.knots))).sort((a, b) => a - b) minKnots = Math.min(...knotValues) maxKnots = Math.max(...knotValues) muValues = Array.from(new Set(bsplineData.map(d => d.mu))).sort((a, b) => a - b) minMu = Math.min(...muValues) maxMu = Math.max(...muValues) // Create a more compact layout for controls viewof controls = Inputs.form({ knots: Inputs.range([minKnots, maxKnots], {value: minKnots, step: 1, label: "Knots:", width: 200}), mu: Inputs.range([minMu, maxMu], {value: 0.5, step: 0.1, label: "μ:", width: 200}) }, { submit: false, layout: 'horizontal', style: 'display: flex; gap: 20px; align-items: center; margin-bottom: 10px; font-size: 0.9em;' }) selectedKnots = controls.knots selectedMu = controls.mu filteredBspline = bsplineData.filter(function(row) { return selectedKnots == row.knots && Math.abs(selectedMu - row.mu) < 0.001; }) ``` ```{ojs} // D3-based visualization for B-spline basis functions chart = { // Create chart dimensions const width = 800; const height = 400; const margin = {top: 40, right: 20, bottom: 40, left: 40}; const innerWidth = width - margin.left - margin.right; const innerHeight = height - margin.top - margin.bottom; // Create scales const x = d3.scaleLinear() .domain([0, 1]) .range([0, innerWidth]); const y = d3.scaleLinear() .domain([0, 0.7]) .range([innerHeight, 0]); // Create a color scale for the basis functions const color = d3.scaleOrdinal(d3.schemeCategory10); // Create SVG const svg = d3.create("svg") .attr("width", width) .attr("height", height) .attr("viewBox", [0, 0, width, height]) .attr("style", "max-width: 100%; height: auto;"); // Add chart title svg.append("text") .attr("class", "chart-title") .attr("x", width / 2) .attr("y", 20) .attr("text-anchor", "middle") .attr("font-size", "16px") .attr("font-weight", "bold"); // Create the chart group const g = svg.append("g") .attr("transform", `translate(${margin.left},${margin.top})`); // Add axes const xAxis = g.append("g") .attr("transform", `translate(0,${innerHeight})`) .call(d3.axisBottom(x).ticks(10)); const yAxis = g.append("g") .call(d3.axisLeft(y).ticks(5)); // Add axis labels g.append("text") .attr("x", innerWidth / 2) .attr("y", innerHeight + 35) .attr("text-anchor", "middle") .text("x"); g.append("text") .attr("transform", "rotate(-90)") .attr("x", -innerHeight / 2) .attr("y", -30) .attr("text-anchor", "middle") .text("y"); // Add a horizontal line at y = 0 g.append("line") .attr("x1", 0) .attr("x2", innerWidth) .attr("y1", y(0)) .attr("y2", y(0)) .attr("stroke", "#000") .attr("stroke-opacity", 0.2); // Add gridlines g.append("g") .attr("class", "grid-lines") .selectAll("line") .data(y.ticks(5)) .join("line") .attr("x1", 0) .attr("x2", innerWidth) .attr("y1", d => y(d)) .attr("y2", d => y(d)) .attr("stroke", "#ccc") .attr("stroke-opacity", 0.5); // Create a line generator const line = d3.line() .x(d => x(d.x)) .y(d => y(d.y)); // Group to contain the basis function lines const linesGroup = g.append("g") .attr("class", "basis-functions"); // Function to update the chart with new data function updateChart(data) { // Group data by basis function const groupedData = d3.group(data, d => d.b); // Update the chart title svg.select(".chart-title") .text(`B-spline Basis Functions (${selectedKnots} knots, μ = ${selectedMu})`); // Update or create paths const paths = linesGroup.selectAll("path") .data(Array.from(groupedData.values())); // Remove paths that are no longer needed paths.exit().remove(); // Add new paths paths.enter() .append("path") .attr("fill", "none") .attr("stroke-width", 3) .attr("stroke", (_, i) => color(i)) .merge(paths) // Merge with existing paths for transition .transition() .duration(750) .attr("d", line); } // Store the update function svg.node().update = updateChart; // Initial render updateChart(filteredBspline); return svg.node(); } ```