Notebooks 2.0 is here.

Published
Edited
May 5, 2020
Insert cell
md`# Bitmap Indices

This notebook demonstrates some of the bitmap index work in yt-4.0`
Insert cell
function zorderXY(points, level) {
// We will do the silly thing here! We'll just do left/right, left/right, left/right
// the domain will be 0 .. 1
var rv = [];
var dims = points[0].length;
points.forEach( (v, i) => {
var center = {x: 0.5, y: 0.5};
var width = {x: 0.5, y: 0.5};
var index = 0;
for (var l = 0; l < level; l++) {
for (const d of ["x", "y"]) {
index = index << 1;
if ( v[d] > center[d] ) {
index |= 1
center[d] += width[d]/2.0;
} else {
center[d] -= width[d]/2.0;
}
width[d] /= 2.0;
}
}
v.zInd = index;
});
return rv;
}
Insert cell
d3 = require("d3");
Insert cell
seedrandom = require("seedrandom");
Insert cell
particles = {
var p = await FileAttachment("gal30_subset_particles.json").json();
var xExtent = d3.extent(p, v => v.x);
var yExtent = d3.extent(p, v => v.y);
var xScale = d3.scaleLinear().domain(xExtent).range([0.0, 1.0]);
var yScale = d3.scaleLinear().domain(yExtent).range([0.0, 1.0]);
p.forEach( (v, i) => {
v.x = xScale(v.x);
v.y = yScale(v.y);
});
zorderXY(p, 4);
return p;
}
Insert cell
{
const margin = 80;
const height = 500;
const width = 500;
const levels = 5;
const nPoints = 1000;
const nDims = 2;
const top_div = d3.create("div").attr("id", "point_container");
const svg = top_div.append("svg").attr("height", height).attr("width", width);
const text_div = top_div.append("div").attr("class", "point_text").style("margin-top", `${margin}px`);

/*const c1 = "#1b9e77";
const c2 = "#d95f02";*/
const c1 = "#46219D";
const c2 = "#789d21";
/*const c1 = "#fd9ad0";
const c2 = "#ecac94";*/

var xScale = d3.scaleLinear().domain([0.0, 1.0]).range([margin, width - margin]).nice();
var yScale = d3.scaleLinear().domain([0.0, 1.0]).range([margin, height - margin]).nice();
var circles = svg.selectAll("circle")
.data(particles)
.enter()
.append("circle")
.attr("cx", v => xScale(v.x))
.attr("cy", v => yScale(v.y))
.attr("r", 1.5)
.style("fill", v => v.g % 2 == 0 ? c1 : c2)
.style("stroke-width", 2.0);
// draw the quad tree
var boxData = [];
var boxElements = [];
var boxSelectors = [];
for (var l = 0; l < 5; l++) {
var lBox = svg.append("g").attr("id", "level-" + l);
var lWidth = (1.0)/Math.pow(2, l);
var lHeight = (1.0)/Math.pow(2, l);
var thisBoxData = [];
var thisBoxElements = [];
boxData.push(thisBoxData);
boxElements.push(thisBoxElements);
for (var xi = 0; xi < Math.pow(2, l); xi++) {
var x = xScale(xi * lWidth);
var rWidth = Math.abs(x - xScale((xi + 1) * lWidth));
for (var yi = 0; yi < Math.pow(2, l); yi++) {
var myInd = 0;
for (var l_ = 0 ; l_ <= l; l_++) {
myInd = myInd << 1;
myInd |= ((xi >> (l - l_)) & 1);
myInd = myInd << 1;
myInd |= ((yi >> (l - l_)) & 1);
}
var y = yScale(yi * lHeight);
var rHeight = Math.abs(y - yScale((yi + 1) * lHeight));
thisBoxData.push( {'level': l, 'x0': x, 'x1': x + rWidth, 'y0': y, 'y1': y + rHeight, 'zInd': myInd});
var thisBox = lBox.append("rect")
.attr("x", x)
.attr("y", y)
.attr("class", "indexBox level" + l)
.attr("height", rHeight)
.attr("width", rWidth)
.style("fill", "none")
.style("stroke-width", levels - l + 1);
thisBoxElements.push(thisBox);
}
}
boxSelectors.push(lBox.selectAll("rect.indexBox.level"+l).data(thisBoxData));
}

var lastSelected = null;
const label = svg.append("text").attr("x", margin/2).attr("y", margin/2).style("font-family", "monospace");
svg.append("rect")
.attr("class", "quadtree")
.attr("x", xScale.range()[0])
.attr("y", yScale.range()[0])
.attr("width", xScale.range()[1] - xScale.range()[0])
.attr("height", yScale.range()[1] - yScale.range()[0]);
circles
.on("mouseover", (d, i, nodes) => {
var zPad = ("".padStart(nDims * levels, "0") + d.zInd.toString(2)).slice(-1 * levels * nDims);
text_div.html(`index = ${zPad}<br/>x = ${d.x.toFixed(8)}<br/>y = ${d.y.toFixed(8)}`);
if (lastSelected != null) lastSelected.attr("r", 1.5).style("stroke", "none");
lastSelected = d3.select(nodes[i])
.attr("r", 5.0).style("stroke", "black");
for (var l = 0; l < 5; l++) {
boxSelectors[l].classed("highlight", d_ => d_.zInd == (d.zInd >> ((4-l) * 2)));
}
}).on("mouseout", (d, i, nodes) => {
});

return top_div.node();
}
Insert cell
{
/*
var radialGradient1 = svg.append("defs")
.append("radialGradient")
.attr("id", "radial-gradient1");

radialGradient1.append("stop")
.attr("offset", "0%")
.attr("stop-color", c1);

radialGradient1.append("stop")
.attr("offset", "100%")
.attr("stop-color", c1)
.attr("stop-opacity", 0);

var radialGradient2 = svg.append("defs")
.append("radialGradient")
.attr("id", "radial-gradient2");

radialGradient2.append("stop")
.attr("offset", "0%")
.attr("stop-color", c2);

radialGradient2.append("stop")
.attr("offset", "100%")
.attr("stop-color", c2)
.attr("stop-opacity", 0);
*/
}
Insert cell
html`<style>
rect.quadtree {
stroke: black;
fill: none;
}
rect.indexBox {
stroke: none;
}
rect.highlight {
stroke: #444444;
}
div.point_text {
font-family: monospace;
float: right;
text-align: right;
}

</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