Published
Edited
Sep 13, 2021
1 fork
Importers
9 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
pts
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
A=pts.map( pt => poly(pt.x) );
Insert cell
Insert cell
Amat = nd.array(A)
Insert cell
Insert cell
ymat = nd.array(pts.map( pt => ([pt.y])))
Insert cell
Insert cell
svd={
const [u, singVals, vT] = nd.la.svd_decomp(Amat);
return ({u,singVals,vT})
}
Insert cell
Insert cell
viewof u = pt(svd.u,{title:"\\mathbf{U}="})
Insert cell
viewof sigma=pt(nd.la.diag_mat(svd.singVals),{title:"\\mathbf{\\Sigma}="})
Insert cell
viewof vT=pt(svd.vT,{title:"\\mathbf{V}^T="})
Insert cell
Insert cell
pinv={
const v = vT.T;
const singValsRecip = svd.singVals.mapElems( (a_ij, i,j) => i==j ? a_ij : 1./a_ij );
const sigmaInv = nd.la.diag_mat(singValsRecip);
return nd.la.matmul(v, sigmaInv, u.T);
}
Insert cell
Insert cell
beta=nd.la.matmul(pinv,ymat)
Insert cell
Insert cell
poly = (x) => {
const out=[];
for (let i=0; i<=order; i++) {
out.push(x**i);
}
return out;
}
Insert cell
polyStr={
let coeffsStr = "y=";
let formStr = "y=";
for (let i=0; i<=order; i++) {
let c = beta(i,0);
if ( i!=0 && c>=0 ){
coeffsStr += "+";
}
if ( i!=0 ) {
formStr += "+";
}
if ( i > 1 ) {
coeffsStr += `${c.toFixed(3)}x^${i}`;
formStr += `\\beta_${i}x^${i}`;
}
if (i == 1 ) {
coeffsStr += `${c.toFixed(3)}x`;
formStr += `\\beta_1x`;
}
if (i == 0 ) {
coeffsStr += `${c.toFixed(3)}`;
formStr += `\\beta_0`;
}
}
return ({fit:coeffsStr,form:formStr});
}
Insert cell
initialPts=[{x:0,y:0}]
Insert cell
Insert cell
drawPts={
svg.selectAll("circle")
.data(pts)
.join("circle")
.attr("cx", d => xScale(d.x))
.attr("cy", d => yScale(d.y))
.attr("r", ptRad)
.style("fill", "red")
.call(d3.drag()
.subject(function(event, d) { return {x: xScale(d.x), y: yScale(d.y)}; })
.on("drag", function(event, d) {
d.x = xScale.invert(event.x);
d.y = yScale.invert(event.y);
svg.property('value', pts).dispatch('input');
d3.select(this).attr("cx", event.x).attr("cy", event.y);}));
}
Insert cell
ptRad=10
Insert cell
axes=Object({xMin:-1.2,xMax:1.2,yMin:-1.2,yMax:1.2})
Insert cell
xScale = d3.scaleLinear().domain([axes.xMin, axes.xMax]).range([margin.left, width - margin.right]);
Insert cell
yScale = d3.scaleLinear().domain([axes.yMin, axes.yMax]).range([height - margin.bottom, margin.top]);
Insert cell
lineId = "fitline"
Insert cell
addline = {
if (svg.select("#"+lineId).empty()) {
svg.append("path")
.attr("id", lineId)
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 2.)
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round");
}
svg.select("#"+lineId)
.datum(data)
.attr("d", d3.line()
.x(d => xScale(d.x))
.y(d => yScale(d.y)));
}
Insert cell
xDomain=d3.extent(pts.map( pt => pt.x))
Insert cell
xMin=xDomain[0]
Insert cell
xMax=xDomain[1]
Insert cell
x=d3.range(npts).map( d => xMin + d/(npts-1)*(xMax-xMin) )
Insert cell
y=x.map( x=> (nd.la.matmul(nd.array([poly(x)]),beta)(0,0) ))
Insert cell
data = x.map( (x,i) => ({x:x, y:y[i]}) )
Insert cell
npts=100
Insert cell
margin = ({top: 20, right: 30, bottom: 30, left: 40})
Insert cell
height=500
Insert cell
nd=require("https://bundle.run/nd4js@1.3.0")
Insert cell
import { pt } from "@fil/pt"
Insert cell
import {slider, button} from "@jashkenas/inputs"
Insert cell
d3 = require("d3@7")
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more