Public
Edited
Feb 6
6 stars
Insert cell
Insert cell
Insert cell
Insert cell
viewof take_step = {
let button = Inputs.button("Start");
d3.select(button).on("click", function () {
let v = button.value;
if (v == 11) {
button.value = 0;
d3.select(button).select("button").text("Restart");
d3.select(diagram)
.selectAll(`.step`)
// .attr("opacity", 1)
.transition()
.duration(200)
.attr("opacity", 0);
} else if (v == 9) {
d3.select(diagram)
.selectAll(`.fade9`)
.attr("opacity", 1)
.transition()
.duration(300)
.attr("opacity", 0.2);
} else if (v == 10) {
d3.select(diagram)
.selectAll(`.highlight9`)
.attr("opacity", 1)
.transition()
.duration(300)
.attr("opacity", 0.2);
d3.select(diagram)
.selectAll(`.highlight10`)
.attr("opacity", 0.2)
.transition()
.duration(300)
.attr("opacity", 1);
} else {
if (v == 1) {
d3.select(button).select("button").text("Next step");
} else if (v == 10) {
d3.select(button).select("button").text("Redo");
}
d3.select(diagram)
.selectAll(`.step${v}`)
.attr("opacity", 0)
.transition()
.duration(400)
.attr("opacity", 1);
}
});
return button;
}
Insert cell
comment = html`<div>
${
[
md`Scroll down a bit and hit the Start button to walk through the proof!`,
md`We start with a single right triangle containing the angle ${tex`\alpha`}.`,
md`We then place a second right triangle with angle ${tex`\beta`} whose base lies along the hypotenuse of the first.`,
md`We can enclose the whole figure inside a rectangle.`,
md`And we can assume that the whole thing is scaled so that the hypotenuse of the second right triangle has length ${tex`1`}.`,
md`Now, note that the new triangle in the upper right has another angle whose measure is ${tex`\alpha`} since it's also complementary to the angle ${tex`\alpha'`}.`,
md`Similarly, the new triangle in the upper left has an angle whose measure is ${tex`\alpha+\beta`} since it's complementary to the angle ${tex`\gamma`}.`,
md`Now we can use the basic definitions of the trig functions to express the lengths of the legs of the second triangle as ${tex`\cos(\beta)`} and ${tex`\sin(\beta)`}.`,
md`And, in fact, we can do the same thing to find the lengths of all the other unlabled sides.`,
md`Finally, simply comparing the total lengths of the left and right sides of the rectangle, we see that
${tex.block`\sin(\alpha+\beta) = \sin(\alpha)\cos(\beta) + \cos(\alpha)\sin(\beta).`}`,
md`Similarly, we can compare the lengths of the top and bottom of the rectangle, to see that
${tex.block`\cos(\alpha+\beta) = \cos(\alpha)\cos(\beta) - \sin(\alpha)\sin(\beta).`}`,
md`Hit the Restart button to walk through the proof again!`
][take_step]
}
</div>`
Insert cell
diagram = {
let deg = Math.PI / 180;
let alpha = 25 * deg;
let beta = 35 * deg;
let sa = Math.sin(alpha);
let sb = Math.sin(beta);
let sab = Math.sin(alpha + beta);
let ca = Math.cos(alpha);
let cb = Math.cos(beta);
let cab = Math.cos(alpha + beta);

let xmax = ca * cb;
let ymax = sab;
let pad = 0.05;
let d = 0.05 * xmax;

let w = 700; //width < 700 ? width : 700;
let h = ((ymax + 2 * pad) / (xmax + 2 * pad)) * w;

let plot = Plot.plot({
x: { domain: [-pad, xmax + pad], ticks: 0 },
y: { domain: [-pad, ymax + pad], ticks: 0 },
width: w,
height: h,
marks: [
// Step 1, the first triangle
Plot.line(
[
[0, 0],
[xmax, 0],
[xmax, sa * cb],
[0, 0]
],
{
fill: "#f1f1f1",
stroke: "black",
strokeWidth: 1,
title: () => "step1"
}
),
// Right angle marker
Plot.line(
[
[xmax, d],
[xmax - d, d],
[xmax - d, 0]
],
{
fill: "none",
stroke: "black",
strokeWidth: 0.5,
title: () => "step1"
}
),
// Alpha angle marker
Plot.line(
[[0, 0]]
.concat(
d3
.range(0, alpha + alpha / 16, alpha / 8)
.map((t) => [2 * d * Math.cos(t), 2 * d * Math.sin(t)])
)
.concat([[0, 0]]),
{
fill: "#FF1200",
stroke: "black",
strokeWidth: 0.5,
title: () => "step1"
}
),

// Step 2, the second triangle
Plot.line(
[
[0, 0],
[xmax, sa * cb],
[cab, ymax],
[0, 0]
],
{
fill: "#d3d3d3",
stroke: "black",
strokeWidth: 1,
title: () => "step2"
}
),
// Right angle marker
Plot.line(
[
[xmax, sa * cb + d],
[xmax - d, sa * cb + d],
[xmax - d, sa * cb]
].map((pt) => rotate(alpha, xmax, sa * cb)(pt)),
{
fill: "none",
stroke: "black",
strokeWidth: 0.5,
title: () => "step2"
}
),
// Beta angle marker
Plot.line(
[[0, 0]]
.concat(
d3
.range(alpha, alpha + beta + beta / 16, beta / 8)
.map((t) => [2.2 * d * Math.cos(t), 2.2 * d * Math.sin(t)])
)
.concat([[0, 0]]),
{
fill: "yellow",
stroke: "black",
strokeWidth: 0.5,
title: () => "step2"
}
),

// Step 3, the containing rectangle
Plot.line(
[
[0, 0],
[xmax, 0],
[xmax, ymax],
[0, ymax],
[0, 0]
],
{
fill: "none",
stroke: "black",
strokeWidth: 3,
title: () => "step3"
}
),

// Step 5 (Step 4 is the 1 implemented in MathJax below)
// The second alpha marker
Plot.line(
[[xmax, sa * cb]]
.concat(
d3
.range(Math.PI / 2, Math.PI / 2 + alpha + alpha / 16, alpha / 8)
.map((t) => [
2 * d * Math.cos(t) + xmax,
2 * d * Math.sin(t) + sa * cb
])
)
.concat([[xmax, sa * cb]]),
{
fill: "#FF1200",
stroke: "black",
strokeWidth: 0.5,
title: () => "step5"
}
),
// The alpha' marker
Plot.line(
d3
.range(Math.PI + alpha, (3 * Math.PI) / 2 + alpha / 16, alpha / 8)
.map((t) => [
1.6 * d * Math.cos(t) + xmax,
1.6 * d * Math.sin(t) + sa * cb
]),
{
fill: "none",
stroke: "black",
strokeWidth: 0.5,
title: () => "step5"
}
),

// Step 6
// The alpha+beta marker
Plot.line(
[[cab, ymax]]
.concat(
d3
.range(
Math.PI,
Math.PI + alpha + beta + alpha / 16,
(alpha + beta) / 8
)
.map((t) => [
2 * d * Math.cos(t) + cab,
2 * d * Math.sin(t) + ymax
])
)
.concat([[cab, ymax]]),
{
fill: "blue",
stroke: "black",
strokeWidth: 0.5,
title: () => "step6"
}
),
// The gamma marker
Plot.line(
d3
.range(alpha + beta, Math.PI / 2 + beta / 16, beta / 8)
.map((t) => [2.4 * d * Math.cos(t), 2.4 * d * Math.sin(t)]),
{
fill: "none",
stroke: "black",
strokeWidth: 0.5,
title: () => "step6"
}
)
]
});

// Add the LaTeX snippets
let s = 2;

// Step 1
let alpha_snippet = MathJax.tex2svg(String.raw`\alpha`).querySelector("svg");
d3.select(plot)
.append("g")
.attr("class", "step step1 fade9")
.attr("transform", `translate(${0.2 * w}, ${0.89 * h}) scale(${s})`)
.append(() => alpha_snippet);

// Step 2
let beta_snippet = MathJax.tex2svg(String.raw`\beta`).querySelector("svg");
d3.select(plot)
.append("g")
.attr("class", "step step2 fade9")
.attr("transform", `translate(${0.18 * w}, ${0.84 * h}) scale(${s})`)
.append(() => beta_snippet);

// Step 4
let one_snippet = MathJax.tex2svg(String.raw`1`).querySelector("svg");
d3.select(plot)
.append("g")
.attr("class", "step step4 fade9")
.attr("transform", `translate(${0.375 * w}, ${0.45 * h}) scale(${s})`)
.append(() => one_snippet);

// Step 5
let alpha_snippet2 = MathJax.tex2svg(String.raw`\alpha`).querySelector("svg");
d3.select(plot)
.append("g")
.attr("class", "step step5 fade9")
.attr("transform", `translate(${0.889 * w}, ${0.493 * h}) scale(${s})`)
.append(() => alpha_snippet2);
let alpha_prime_snippet = MathJax.tex2svg(String.raw`\alpha'`).querySelector(
"svg"
);
d3.select(plot)
.append("g")
.attr("class", "step step5 fade9")
.attr("transform", `translate(${0.861 * w}, ${0.633 * h}) scale(${s})`)
.append(() => alpha_prime_snippet);

// Step 6
let alpha_plus_beta_snippet = MathJax.tex2svg(
String.raw`\alpha+\beta`
).querySelector("svg");
d3.select(plot)
.append("g")
.attr("class", "step step6 fade9")
.attr("transform", `translate(${0.495 * w}, ${0.105 * h}) scale(${s})`)
.append(() => alpha_plus_beta_snippet);
let gamma_snippet = MathJax.tex2svg(String.raw`\gamma`).querySelector("svg");
d3.select(plot)
.append("g")
.attr("class", "step step6 fade9")
.attr("transform", `translate(${0.13 * w}, ${0.81 * h}) scale(${s})`)
.append(() => gamma_snippet);

// Step 7
let cosb_snippet = MathJax.tex2svg(String.raw`\cos(\beta)`).querySelector(
"svg"
);
d3.select(plot)
.append("g")
.attr("class", "step step7 fade9 fade10")
.attr("transform", `translate(${0.5 * w}, ${0.7 * h}) scale(${s})`)
.append(() => cosb_snippet);
let sinb_snippet = MathJax.tex2svg(String.raw`\sin(\beta)`).querySelector(
"svg"
);
d3.select(plot)
.append("g")
.attr("class", "step step7 fade9 fade10")
.attr("transform", `translate(${0.73 * w}, ${0.35 * h}) scale(${s})`)
.append(() => sinb_snippet);

// Step 8
let cosa_cosb_snippet = MathJax.tex2svg(
String.raw`\cos(\alpha)\cos(\beta)`
).querySelector("svg");
d3.select(plot)
.append("g")
.attr("class", "step step8 fade9 highlight10")
.attr("transform", `translate(${0.45 * w}, ${0.885 * h}) scale(${s})`)
.append(() => cosa_cosb_snippet);
let sina_sinb_snippet = MathJax.tex2svg(
String.raw`\sin(\alpha)\sin(\beta)`
).querySelector("svg");
d3.select(plot)
.append("g")
.attr("class", "step step8 fade9 highlight10")
.attr("transform", `translate(${0.72 * w}, ${0.04 * h}) scale(${s})`)
.append(() => sina_sinb_snippet);
let cos_aplusb_snippet = MathJax.tex2svg(
String.raw`\cos(\alpha+\beta)`
).querySelector("svg");
d3.select(plot)
.append("g")
.attr("class", "step step8 fade9 highlight10")
.attr("transform", `translate(${0.3 * w}, ${0.04 * h}) scale(${s})`)
.append(() => cos_aplusb_snippet);

// More step 8!
let sin_aplusb_snippet = MathJax.tex2svg(
String.raw`\sin(\alpha+\beta)`
).querySelector("svg");
d3.select(plot)
.append("g")
.attr("class", "step step8 highlight9 fade10")
.attr("transform", `translate(${0.13 * w}, ${0.33 * h}) scale(${s})`)
.append("g")
.append(() => sin_aplusb_snippet);
let cosa_sinb_snippet = MathJax.tex2svg(
String.raw`\cos(\alpha)\sin(\beta)`
).querySelector("svg");
d3.select(plot)
.append("g")
.attr("class", "step step8 highlight9 fade10")
.attr("transform", `translate(${0.775 * w}, ${0.2 * h}) scale(${s})`)
.append(() => cosa_sinb_snippet);
let sina_cosb_snippet = MathJax.tex2svg(
String.raw`\sin(\alpha)\cos(\beta)`
).querySelector("svg");
d3.select(plot)
.append("g")
.attr("class", "step step8 highlight9 fade10")
.attr("transform", `translate(${0.775 * w}, ${0.77 * h}) scale(${s})`)
.append(() => sina_cosb_snippet);

// Translate the titles to classes and then remove the titles.
d3.select(plot)
.selectAll("g")
.nodes()
.forEach(function (node) {
let nodeD3 = d3.select(node);
let title = nodeD3.select("title");
try {
let text = title.text();
if (text.length > 4 && text.slice(0, 4) == "step") {
nodeD3.attr("class", `step ${text}`);
title.remove();
}
} catch {
("pass");
}
});

// Hide everything to start.
d3.select(plot).selectAll(".step").attr("opacity", 0);

return plot;
}
Insert cell
Insert cell
function rotate(t, x0, y0) {
return function ([x, y]) {
return [
(x - x0) * Math.cos(t) - (y - y0) * Math.sin(t) + x0,
(y - y0) * Math.cos(t) + (x - x0) * Math.sin(t) + y0
];
};
}
Insert cell
MathJax = require("https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js").catch(
() => window["MathJax"]
)
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