Public
Edited
Jan 1, 2024
1 fork
Importers
11 stars
Insert cell
Insert cell
pts = build_samples((x) => Math.sqrt(x) * Math.sin(x ** 2), 0, 5)
Insert cell
Insert cell
Insert cell
Plot.plot({
marks: [
Plot.line(pts),
Plot.ruleX([0]),
Plot.ruleY([-2.2]),
show_points ? Plot.dot(pts, { fill: "black", opacity: 0.5 }) : []
]
})
Insert cell
Insert cell
Plot.plot({
marks: [
Plot.line(
build_samples((x) => Math.sqrt(x) * Math.sin(x ** 2), 0, 22, {
N: 400,
max_depth: 5
})
),
Plot.ruleX([0]),
Plot.ruleY([-4.7])
]
})
Insert cell
Insert cell
Insert cell
Insert cell
pic1 = {
let pts = build_samples((x) => (x < 0 ? Math.sqrt(1 - x ** 2) : 1), -1, 4, {
N: 5,
max_depth: depth
});
let pic = Plot.plot({
width: width,
height: width * 0.24,
marks: [
Plot.line(pts),
Plot.dot(pts, { fill: "black" }),
Plot.ruleX([-1]),
Plot.ruleY([0]),
Plot.text([[1, 0.5]], { x: (d) => d[0], y: (d) => d[1], text: "hi" })
]
});
pic.pt_cnt = pts.length;

return pic;
}
Insert cell
Insert cell
// The main function
// This function breaks the initial interval into N subintervals.
// It then checks the value at the midpoint of each subinterval.
// If the angle between the two segments formed by approximating
// the function over the first half and the second half is greater
// than 0.01 radians, then the interval is subdivided.
// Proceed recursively up to max_depth.

function build_samples(f, a, b, opts = {}) {
let { N = 9, max_depth = 6 } = opts;
let dx = (b - a) / N;
let root_intervals = Array.from({ length: N }).map(
(_, i) => new Interval(a + i * dx, a + (i + 1) * dx, 0)
);
root_intervals.forEach((I) => {
I.fa = f(I.a);
I.fb = f(I.b);
});
root_intervals.reverse();

let stack = root_intervals;
let cnt = 0;
let pts = [];
let nodeRight, nodeLeft;
while (stack.length > 0 && cnt++ < 100000) {
let node = stack.pop();
if (test(f, node, opts)) {
let midpoint = node.midpoint;
let new_depth = node.depth + 1;
if (new_depth <= max_depth) {
let a_left = node.a;
let b_left = midpoint;
nodeLeft = new Interval(a_left, b_left, new_depth);
nodeLeft.fa = f(a_left);
nodeLeft.fb = f(b_left);
node.left = nodeLeft;

let a_right = midpoint;
let b_right = node.b;
nodeRight = new Interval(a_right, b_right, new_depth);
nodeRight.fa = f(a_left);
nodeRight.fb = f(b_left);
node.right = nodeRight;

stack.push(nodeRight);
stack.push(nodeLeft);
} else {
pts.push(node.a);
}
} else {
pts.push(node.a);
}
}
pts.push(b);
// pts = pts.map(x => ({ x: x, y: f(x) }));
pts = pts.map((x) => [x, f(x)]);

if (opts.show_roots) {
let function_roots = [];
pts.forEach(function (o, i) {
if (i < pts.length - 1 && Math.sign(o.y) != Math.sign(pts[i + 1].y)) {
function_roots.push((o.x + pts[i + 1].x) / 2);
}
});
pts.function_roots = function_roots;
}
return pts;
}
Insert cell
function test(f, I, opts = {}) {
let { angle_tolerance = 0.01, check_roots = false } = opts;
let a = I.a;
let b = I.b;
let dx2 = (b - a) / 2;
let m = (a + b) / 2;
let fm = f(m);
I.midpoint = m;
I.f_mid = fm;
if (check_roots && Math.sign(I.fa) != Math.sign(I.fb)) {
return true;
}
let alpha = Math.atan((I.f_mid - I.fa) / dx2);
let beta = Math.atan((I.fb - I.f_mid) / dx2);
return Math.abs(alpha - beta) > angle_tolerance;
}
Insert cell
class Interval {
constructor(a, b, depth) {
this.a = a;
this.b = b;
this.depth = depth;
}
}
Insert cell
// function plot(f, a, b, opts = {}) {
// let { w = width < 800 ? width : 800 } = opts;
// if (opts.show_roots) {
// opts.check_roots = true;
// }
// let pts = build_samples(f, a, b, opts);
// let ymin = d3.min(pts.map((pt) => pt.y));
// let ymax = d3.max(pts.map((pt) => pt.y));
// let to_plot = [
// Plot.line(pts, { x: "x", y: "y" }),
// Plot.ruleX([a]),
// Plot.ruleY([ymin])
// ];
// if (opts.show_points) {
// to_plot.push(Plot.dot(pts, { x: "x", y: "y", fill: "black" }));
// }
// if (opts.show_roots) {
// to_plot.push(
// Plot.dot(
// pts.function_roots.map((x) => ({ x: x, y: 0 })),
// {
// x: "x",
// y: "y",
// fill: "black"
// }
// )
// );
// }
// if (opts.plot_label) {
// to_plot.push(
// Plot.text([[(a + b) / 2, ymax]], {
// text: () => opts.plot_label,
// fontSize: () => 20
// })
// );
// }
// let pic = Plot.plot({
// width: w,
// marks: to_plot
// });
// pic.pt_cnt = pts.length;
// return pic;
// }
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