Make it d3

This commit is contained in:
2025-05-18 01:13:04 +02:00
parent 38c3e5d931
commit 63691f53b1

166
app.qmd
View File

@@ -10,13 +10,15 @@ execute:
highlight-style: github highlight-style: github
--- ---
#### B-spline Basis Functions ## B-spline Basis Functions
```{ojs} ```{ojs}
bsplineData = FileAttachment("basis_functions.csv").csv({ typed: true }) d3 = require("d3@7")
``` ```
```{ojs} ```{ojs}
bsplineData = FileAttachment("basis_functions.csv").csv({ typed: true })
knotValues = Array.from(new Set(bsplineData.map(d => d.knots))).sort((a, b) => a - b) knotValues = Array.from(new Set(bsplineData.map(d => d.knots))).sort((a, b) => a - b)
minKnots = Math.min(...knotValues) minKnots = Math.min(...knotValues)
maxKnots = Math.max(...knotValues) maxKnots = Math.max(...knotValues)
@@ -24,9 +26,7 @@ maxKnots = Math.max(...knotValues)
muValues = Array.from(new Set(bsplineData.map(d => d.mu))).sort((a, b) => a - b) muValues = Array.from(new Set(bsplineData.map(d => d.mu))).sort((a, b) => a - b)
minMu = Math.min(...muValues) minMu = Math.min(...muValues)
maxMu = Math.max(...muValues) maxMu = Math.max(...muValues)
```
```{ojs}
// Create a more compact layout for controls // Create a more compact layout for controls
viewof controls = Inputs.form({ viewof controls = Inputs.form({
knots: Inputs.range([minKnots, maxKnots], {value: minKnots, step: 1, label: "Knots:", width: 200}), knots: Inputs.range([minKnots, maxKnots], {value: minKnots, step: 1, label: "Knots:", width: 200}),
@@ -39,39 +39,141 @@ viewof controls = Inputs.form({
selectedKnots = controls.knots selectedKnots = controls.knots
selectedMu = controls.mu selectedMu = controls.mu
```
```{ojs}
filteredBspline = bsplineData.filter(function(row) { filteredBspline = bsplineData.filter(function(row) {
return selectedKnots == row.knots && Math.abs(selectedMu - row.mu) < 0.001; return selectedKnots == row.knots && Math.abs(selectedMu - row.mu) < 0.001;
}) })
``` ```
```{ojs} ```{ojs}
Plot.plot({ // D3-based visualization for B-spline basis functions
grid: true, chart = {
y: {domain: [0, 0.7]}, // Create chart dimensions
x: {label: "x", domain: [0, 1]}, const width = 800;
marks: [ const height = 400;
Plot.line(filteredBspline, { const margin = {top: 40, right: 20, bottom: 40, left: 40};
x: "x", const innerWidth = width - margin.left - margin.right;
y: "y", const innerHeight = height - margin.top - margin.bottom;
stroke: "b",
strokeWidth: 5, // Create scales
}), const x = d3.scaleLinear()
Plot.ruleY([0]) .domain([0, 1])
], .range([0, innerWidth]);
color: {
legend: false, const y = d3.scaleLinear()
label: "Basis Function" .domain([0, 0.7])
}, .range([innerHeight, 0]);
marginRight: 80,
width: 800, // Create a color scale for the basis functions
height: 400, const color = d3.scaleOrdinal(d3.schemeCategory10);
// title: `B-spline Basis Functions (${selectedKnots} knots, μ = ${selectedMu})`
}) // 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();
}
``` ```
::: {.callout-note}
TODO
:::