viewof scale_a = {
const wrapper = html`<div style="display: flex; align-items: center; gap: 10px;">
<span style="white-space: nowrap; font-size: 14px; font-weight: 500; min-width: 160px;">Scale parameter (a):</span>
</div>`;
const slider = Inputs.range([0.5, 5], {value: 2, step: 0.1, label: ""});
wrapper.appendChild(slider);
// Forward the value property from the slider to the wrapper
Object.defineProperty(wrapper, 'value', {
get: () => slider.value,
set: (v) => { slider.value = v; }
});
['pointerdown', 'touchstart', 'mousedown', 'click', 'wheel', 'pointermove', 'touchmove', 'mousemove'].forEach(e =>
wrapper.addEventListener(e, ev => ev.stopPropagation())
);
return wrapper;
}
viewof shift_b = {
const wrapper = html`<div style="display: flex; align-items: center; gap: 10px;">
<span style="white-space: nowrap; font-size: 14px; font-weight: 500; min-width: 160px;">Shift parameter (b):</span>
</div>`;
const slider = Inputs.range([-2, 5], {value: 1, step: 0.1, label: ""});
wrapper.appendChild(slider);
// Forward the value property from the slider to the wrapper
Object.defineProperty(wrapper, 'value', {
get: () => slider.value,
set: (v) => { slider.value = v; }
});
['pointerdown', 'touchstart', 'mousedown', 'click', 'wheel', 'pointermove', 'touchmove', 'mousemove'].forEach(e =>
wrapper.addEventListener(e, ev => ev.stopPropagation())
);
return wrapper;
}
u_min = shift_b
u_max = scale_a + shift_b
f_u = 1 / scale_a
{
const width = 1000;
const height = 380;
const margin = {top: 40, right: 40, bottom: 60, left: 70};
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("style", "background: white; font-size: 16px;");
const maxX = Math.max(6, u_max + 1);
const minX = -2;
const maxY = Math.max(1.5, f_u + 0.3);
const plotWidth = width - margin.left - margin.right;
const plotHeight = height - margin.top - margin.bottom;
// Equal scale: same pixels per unit on both axes
const pixelsPerUnitX = plotWidth / (maxX - minX);
const pixelsPerUnitY = plotHeight / maxY;
const pixelsPerUnit = Math.min(pixelsPerUnitX, pixelsPerUnitY);
const actualPlotWidth = pixelsPerUnit * (maxX - minX);
const actualPlotHeight = pixelsPerUnit * maxY;
const x = d3.scaleLinear()
.domain([minX, maxX])
.range([margin.left, margin.left + actualPlotWidth]);
const y_scale = d3.scaleLinear()
.domain([0, maxY])
.range([height - margin.bottom, height - margin.bottom - actualPlotHeight]);
// Original Y ~ Uniform(0,1)
svg.append("rect")
.attr("x", x(0))
.attr("y", y_scale(1))
.attr("width", x(1) - x(0))
.attr("height", y_scale(0) - y_scale(1))
.attr("fill", "steelblue")
.attr("opacity", 0.4);
// Transformed U ~ Uniform(b, a+b)
svg.append("rect")
.attr("x", x(u_min))
.attr("y", y_scale(f_u))
.attr("width", x(u_max) - x(u_min))
.attr("height", y_scale(0) - y_scale(f_u))
.attr("fill", "darkred")
.attr("opacity", 0.6);
// Axes
svg.append("g")
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x))
.style("font-size", "14px");
svg.append("g")
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y_scale))
.style("font-size", "14px");
// Labels
svg.append("text")
.attr("x", width / 2)
.attr("y", height - 10)
.attr("text-anchor", "middle")
.style("font-size", "18px")
.text("Value");
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("x", -height / 2)
.attr("y", 20)
.attr("text-anchor", "middle")
.style("font-size", "18px")
.text("Density");
svg.append("text")
.attr("x", width / 2)
.attr("y", 25)
.attr("text-anchor", "middle")
.style("font-size", "20px")
.style("font-weight", "bold")
.text(`Y ~ Uniform(0,1) β U = ${scale_a.toFixed(1)}Y + ${shift_b.toFixed(1)}`);
return svg.node();
}