viewof a11 = Inputs.range([0.5, 3], {
step: 0.1,
value: 2,
label: tex`a_{11}`,
width: 150
})
viewof a12 = Inputs.range([-1, 1], {
step: 0.1,
value: 0.5,
label: tex`a_{12}`,
width: 150
})
viewof a21 = Inputs.range([-1, 1], {
step: 0.1,
value: 0.5,
label: tex`a_{21}`,
width: 150
})
viewof a22 = Inputs.range([0.5, 3], {
step: 0.1,
value: 1.5,
label: tex`a_{22}`,
width: 150
})
// Calculate eigenvalues and eigenvectors
eigenData = {
const trace = a11 + a22;
const det = a11 * a22 - a12 * a21;
const discriminant = trace * trace - 4 * det;
// Calculate eigenvalues
const lambda1 = (trace + Math.sqrt(Math.abs(discriminant))) / 2;
const lambda2 = (trace - Math.sqrt(Math.abs(discriminant))) / 2;
// Calculate eigenvectors
let v1, v2;
// For λ₁
if (Math.abs(a12) > 1e-10) {
v1 = [1, -(a11 - lambda1) / a12];
} else if (Math.abs(a21) > 1e-10) {
v1 = [-(a22 - lambda1) / a21, 1];
} else {
v1 = [1, 0];
}
// For λ₂
if (Math.abs(a12) > 1e-10) {
v2 = [1, -(a11 - lambda2) / a12];
} else if (Math.abs(a21) > 1e-10) {
v2 = [-(a22 - lambda2) / a21, 1];
} else {
v2 = [0, 1];
}
// Normalize to unit vectors
const norm1 = Math.sqrt(v1[0] * v1[0] + v1[1] * v1[1]);
const norm2 = Math.sqrt(v2[0] * v2[0] + v2[1] * v2[1]);
v1 = [v1[0] / norm1, v1[1] / norm1];
v2 = [v2[0] / norm2, v2[1] / norm2];
return { lambda1, lambda2, v1, v2 };
}
// Display matrix and eigenvalue information
html`<div style="text-align: center; font-size: 1.2em; margin: 1.5em 0;">
<p>
${tex`\mathbf{A} = \begin{bmatrix} ${a11.toFixed(1)} & ${a12.toFixed(1)} \\ ${a21.toFixed(1)} & ${a22.toFixed(1)} \end{bmatrix}`}
</p>
<p style="margin-top: 1em;">
${tex`\lambda_1 = ${eigenData.lambda1.toFixed(3)}, \quad \lambda_2 = ${eigenData.lambda2.toFixed(3)}`}
</p>
<p style="margin-top: 0.5em; font-size: 0.9em;">
${tex`\mathbf{v}_1 = \begin{bmatrix} ${eigenData.v1[0].toFixed(3)} \\ ${eigenData.v1[1].toFixed(3)} \end{bmatrix}, \quad \mathbf{v}_2 = \begin{bmatrix} ${eigenData.v2[0].toFixed(3)} \\ ${eigenData.v2[1].toFixed(3)} \end{bmatrix}`}
</p>
</div>`Plot.plot({
style: "overflow: visible; display: block; margin: 0 auto;",
width: 600,
height: 600,
grid: true,
x: {label: "x₁", domain: [-4, 4]},
y: {label: "x₂", domain: [-4, 4]},
marks: [
// Grid axes
Plot.ruleY([0], {stroke: "#ddd", strokeWidth: 1}),
Plot.ruleX([0], {stroke: "#ddd", strokeWidth: 1}),
// First eigenvector (red solid)
Plot.arrow([{x1: 0, y1: 0, x2: eigenData.v1[0] * 2, y2: eigenData.v1[1] * 2}], {
x1: "x1", y1: "y1", x2: "x2", y2: "y2",
stroke: "#d73027", strokeWidth: 4, fill: "#d73027"
}),
// First eigenvector scaled by eigenvalue (red dotted)
Plot.arrow([{x1: 0, y1: 0, x2: eigenData.v1[0] * 2 * eigenData.lambda1, y2: eigenData.v1[1] * 2 * eigenData.lambda1}], {
x1: "x1", y1: "y1", x2: "x2", y2: "y2",
stroke: "#d73027", strokeWidth: 4, fill: "#d73027",
strokeDasharray: "8,4"
}),
// Second eigenvector (green solid)
Plot.arrow([{x1: 0, y1: 0, x2: eigenData.v2[0] * 2, y2: eigenData.v2[1] * 2}], {
x1: "x1", y1: "y1", x2: "x2", y2: "y2",
stroke: "#1a9850", strokeWidth: 4, fill: "#1a9850"
}),
// Second eigenvector scaled by eigenvalue (green dotted)
Plot.arrow([{x1: 0, y1: 0, x2: eigenData.v2[0] * 2 * eigenData.lambda2, y2: eigenData.v2[1] * 2 * eigenData.lambda2}], {
x1: "x1", y1: "y1", x2: "x2", y2: "y2",
stroke: "#1a9850", strokeWidth: 4, fill: "#1a9850",
strokeDasharray: "8,4"
}),
// Origin point
Plot.dot([{x: 0, y: 0}], {
x: "x", y: "y",
r: 5,
fill: "black",
stroke: "white", strokeWidth: 2
}),
// Eigenvector labels
Plot.text([
{x: eigenData.v1[0] * 2.3, y: eigenData.v1[1] * 2.3, text: `v₁`},
{x: eigenData.v2[0] * 2.3, y: eigenData.v2[1] * 2.3, text: `v₂`}
], {
x: "x", y: "y", text: "text",
fontSize: 14, fontWeight: "bold",
fill: d => d.text.includes("₁") ? "#d73027" : "#1a9850"
}),
// Eigenvalue scaling labels
Plot.text([
{x: eigenData.v1[0] * 2.3 * eigenData.lambda1 + 0.2, y: eigenData.v1[1] * 2.3 * eigenData.lambda1 + 0.2, text: `λ₁v₁`},
{x: eigenData.v2[0] * 2.3 * eigenData.lambda2 + 0.2, y: eigenData.v2[1] * 2.3 * eigenData.lambda2 + 0.2, text: `λ₂v₂`}
], {
x: "x", y: "y", text: "text",
fontSize: 12, fontWeight: "bold",
fill: d => d.text.includes("₁") ? "#d73027" : "#1a9850"
})
]
})