Public
Edited
Feb 27, 2023
1 fork
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
settings = {
const wide = 16;
const tall = 9;
const resolution = width / wide;
const height = width * tall / wide;
const top = 1;
const plotY = top * resolution;
return ({
...controls,
...themes[controls.theme],
width,
height,
plotY,
top: 1,
wide,
tall,
top,
})
}
Insert cell
themes = {
const darkChannelColors = ["gold", "lime", "orange"];
return {
black: {stroke: "#8FFBEA", backgroundColor: "black", channels: darkChannelColors, gridStroke: "white"},
white: {stroke: "black", backgroundColor: "white", channels: d3.schemeCategory10, gridStroke: "black"},
phosphor: {stroke: "#89f5fe", backgroundColor: "#112B17", channels: darkChannelColors, gridStroke: "grey"},
phosphor2: {stroke: "#A1F4EC", backgroundColor: "#4E80AD", channels: ["#A1F4EC"], gridStroke: "black"},
}
}
Insert cell
Insert cell
Insert cell
v = (
({VIN, A, phi, ƒ, tmax}) =>
(t) =>
VIN + A * Math.sin(Math.PI * (2 * t * (tmax/(1000/settings.ƒ)) + phi))
)
(settings)
Insert cell
scary = () => {
const {VIN, A, t, phi, ƒ} = settings;
const {abs} = Math;
const sign = (x) => x >= 0 ? "+" : "-";
const term = (x) => `${sign(x)} ${f2(abs(x))}`;
return tex`v_{IN}(t) = V_{IN} + v_{in}(t) = ${f2(VIN)} ${term(A)}\sin(\pi(2\cdot${f2(ƒ)} ${term(phi)}))`;
}
Insert cell
Insert cell
Insert cell
{
const {magnitude} = scale;
const f = d3.format("~s");
const m = 10 ** magnitude;
return ({
magnitude,
scale: f(m) + "s/div",
value: f(3 * m),
})
}
Insert cell
Insert cell
formula =
({stroke}) => // settings
(f) =>
(panel) =>
{
// source: https://observablehq.com/@mcmcclur/overlay-katex-on-top-of-an-svg
const {width} = settings;
d3
.select(f)
.style("float", "right")
.style("padding-right", "18px")
;
panel
.append("div")
.attr("name", "formula")
.style("position", "absolute")
.style("width", `${width}px`)
.style("top", `18px`)
.style("color", stroke)
.append(() => f)
;
}
Insert cell
ch =
({channels, backgroundColor}) => // settings
({number, value = "", unit = ""} = {}) =>
(panel) =>
{
const c = color(channels)(number);
const n = number + 1;
const g = panel
.append("g")
.attr("name", `channel ${n}`)
.attr("transform", `translate(72,${24 * n})`)
;
g
.append("path")
.style("stroke", c)
.style("stroke-width", 18)
.attr("d", `M0 0H45`)
;
g
.append("text")
.text(`CH${n}:`)
.attr("fill", backgroundColor)
.attr("dx", 2)
.attr("dy", 4)
.style("font-family", "monospace")
.style("font-weight", 900)
;
g
.append("text")
.text(`${value}${unit}`)
.attr("fill", c)
.attr("dx", 54)
.attr("dy", 4)
.style("font-family", "monospace")
.style("font-weight", 900)
;
return g;
}
Insert cell
color = (channels) => (number) => channels[number % channels.length];
Insert cell
Insert cell
plot = (settings) => (data) => {
const {VIN, stroke, height, backgroundColor, t, tmax, plotY = 72, gridStroke, channels} = settings;
const y = v(t / tmax);
const x = t;
const axis = ({
stroke,
textStroke: "transparent",
fill: stroke,
});

const p = Plot.plot(
{
width, height: height - plotY,
style: {
backgroundColor,
stroke,
},
axis: null,
x:{
label: "→ time (ms)",
},
y: {
nice: true,
label: "↑ voltage (V)",
},
marks: [
grid({stroke: gridStroke, tmax, axis}),
cursor(settings)({x, y}),
Plot.line(data, {x: "t", y: "u", stroke: color(channels)(0)}),
Plot.line([{x: 0, y: VIN}, {x: tmax, y: VIN}], {x: "x", y: "y", stroke: color(channels)(1)}),
]
}
);
d3.select(p).attr("y", plotY); // make space for global values
return p;
}
Insert cell
cursor =
({stroke = "#8FFBEA", strokeDasharray = 3} = {}) =>
({x, y} = {}) =>
[
Plot.ruleX([x], {stroke, strokeDasharray}),
Plot.ruleY([y], {stroke, strokeDasharray}),
Plot.text([0], {
text: () => `(${x.toFixed(2)}, ${y.toFixed(2)})`,
x, dx: 6 * [+1, -1][side],
y, dy: -9,
textAnchor: ["start", "end"][side],
}),
]
Insert cell
grid = ({tmax, axis, stroke = "grey"}) => [
Plot.gridX({stroke, strokeOpacity: .5}),
Plot.gridY({stroke, strokeOpacity: .5}),
Plot.axisX(axis),
Plot.axisY(d3.ticks(0,10,5), axis),
]
Insert cell
Insert cell
side = ((t, tmax) => (t < tmax / 2 ? 0 : 1))(settings.t, settings.tmax);
Insert cell
f2 = (x) => x.toFixed(2);
Insert cell
// used by Inputs.form at top
template = (inputs) => htl.html`<div class="styled">${Object.values(inputs)}</div>
<style>
div.styled { text-align: right; column-count: 2; }
div.styled form>label { font-weight: bold; }
div.styled label:not(div>label):after { content: ":"; }
</style>`
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