Published
Edited
Oct 26, 2019
3 stars
Insert cell
md`# Volume Grammar`
Insert cell
{
const svg = d3.create("svg").attr("viewBox", [-width / 2, -height / 2, width, height]);
var cellData = rootGrid.concat(refinedData);
var cells = createPaths(cfg, cellData);
var interpolators = [flubber.interpolateAll(cells.disk, cells.memory),
flubber.interpolateAll(cells.memory, cells.cyl),
flubber.interpolateAll(cells.cyl, cells.disk)];
var cellColor = d3.scaleSequential(d3.interpolateSpectral).domain([0, cellData.length - 1]);
svg.selectAll("path")
.data(cellData)
.enter()
.append("path")
.attr("stroke", "black")
.attr("fill", (d, flatIndex) => cellColor(flatIndex))
.attr("fill-opacity", 0.75)
.attr("d", (d, path_i) => cells.disk[path_i]);
yield svg.node();
var transitionIndex = 0;
while (true) {
await svg.selectAll("path")
.data(cellData)
.transition()
.delay((d, flatIndex) => (flatIndex + 1) * 10)
.duration(2000)
.attrTween("d", function(d, path_i) { return interpolators[transitionIndex % 3][path_i]})
.end();
await Promises.delay(5000);
yield svg.node();
transitionIndex += 1;
}
}
Insert cell
{
var svg = d3.create("svg").attr("viewBox", [-width / 2, -height / 2, width, height]);
var complexConfig = defaultConfig([32, 32], [ [ [-128.0, 128.0], [ 20.0, 200.0 ] ],
[ [-128.0, 128.0], [ 0.0, Math.PI ] ] ] );
var cellData = createCells(complexConfig, 0, [32, 32], [0, 0], 0);
cellData.forEach( d => d.value = kh[d.j][d.i] );
var cellPaths = createPaths(complexConfig, cellData, 10);
var cellColor = d3.scaleSequential(d3.interpolateViridis).domain([0.95, 2.15]);
console.log(cellData[0]);
console.log(complexConfig);
svg.selectAll("path")
.data(cellData)
.enter()
.append("path")
.attr("stroke", "lightgrey")
.attr("stroke-width", 1.0)
.attr("stroke-opacity", 0.5)
.attr("fill", (d, flatIndex) => cellColor(d.value))
.attr("fill-opacity", 1.0)
.attr("d", (d, path_i) => cellPaths.memory[path_i]);
yield svg.node();
await Promises.delay(5000);
svg.selectAll("path")
.data(cellData)
.transition()
.duration(2000)
.attr("fill-opacity", d => (d.value > 1.5 ? 0.85 : 0.5))
.attr("transform", "translate(-100, 0)");
}
Insert cell
{
var svg = d3.create("svg").attr("viewBox", [-width/2, -height/2, width, height]);
yield svg.node();
var complexConfig = defaultConfig([32, 32], [ [ [-128.0, 128.0], [ 20.0, 200.0 ] ],
[ [-128.0, 128.0], [ 0.0, Math.PI ] ] ] );
var cellData = createCells(complexConfig, 0, [32, 32], [0, 0], 0);
var fields = ["density", "temperature", "velocity_x", "velocity_y",
"velocity_z", "velocity_magnitude"];
var extents = {};
fields.forEach( v => {
cellData.forEach( d => {
d[v] = galaxy0030[v][d.j][d.i]
})
extents[v] = d3.extent(cellData, d=>d[v]);
});
var cellPaths = createPaths(complexConfig, cellData, 10);
var vel_fields = [extents["velocity_x"], extents["velocity_y"], extents["velocity_z"]];
extents["velocity_total"] = [d3.min(vel_fields, d=>d[0]), d3.max(vel_fields, d=>d[1])];
var colorScales = {
density: d3.scaleSequentialLog(d3.interpolateViridis).domain(extents["density"]),
temperature: d3.scaleSequentialLog(d3.interpolateInferno).domain(extents["temperature"]),
velocity_x: d3.scaleSequentialSymlog(d3.interpolateRdBu).domain(extents["velocity_total"]),
velocity_y: d3.scaleSequentialSymlog(d3.interpolateRdBu).domain(extents["velocity_total"]),
velocity_z: d3.scaleSequentialSymlog(d3.interpolateRdBu).domain(extents["velocity_total"]),
velocity_magnitude: d3.scaleSequentialLog(d3.interpolateReds).domain(extents["velocity_magnitude"])
};
console.log(extents);
svg.selectAll("path")
.data(cellData)
.enter()
.append("path")
.attr("stroke", "lightgrey")
.attr("stroke-width", 1.0)
.attr("stroke-opacity", 0.5)
.attr("fill-opacity", 1.0)
.attr("d", (d, path_i) => cellPaths.memory[path_i])
.attr("fill", (d) => (colorScales["density"](d["density"])));
await Promises.delay(2500);
for (var vi = 0; vi < fields.length ; vi++) {
var v = fields[vi];
svg.selectAll("path")
.data(cellData)
.transition()
.duration(2000)
.attr("stroke", "lightgrey")
.attr("fill", (d) => (colorScales[v](d[v])))
.attr("fill-opacity", 1.0)
.attr("d", (d, path_i) => cellPaths.memory[path_i]);
yield svg.node();
await Promises.delay(5000);
};
}
Insert cell
{
var svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
var cellData = kelvinHelmholtzAMR.cellData;
var cellPaths = kelvinHelmholtzAMR.cellPaths;
var tree = kelvinHelmholtzAMR.tree;
var cellColor = d3.scaleSequential(d3.interpolateViridis).domain([0.95, 2.15]);
var cellColorBW = d3.scaleSequential(d3.interpolateGreys).domain([0.95, 2.15]);
cellData.forEach( d => d.selected = false);
var maxCells = d3.max(d3.nest().key(d => d.level).rollup(d => d.length).entries(cellData), d=>d.value);
function brushed() {
var extent = d3.event.selection;
var newLevels = new Array(3).fill(0);
tree.visit(findOverlappingNodesRect(extent, nd => {
newLevels[nd.level] += 1;
nd.selected = true;
}));
imageRect.filter(d=>!d.selected)
.style("fill", d => cellColorBW(d.density))
imageRect.filter(d=>d.selected)
.style("fill", d => cellColor(d.density))
.each(d=>{d.selected=false;});
svg.select("g#barchart")
.selectAll("rect")
.data(newLevels)
.transition()
.attr("y", d=> histY(d))
.attr("height", d => height - (32 + histY(d)));
}
var histY = d3.scaleLinear()
.domain([0, maxCells]).nice()
.range([height - 32, 32]);
var histX = d3.scaleBand()
.domain([0, 1, 2])
.range([512 + 48, width - 64])
.padding(0.1)
svg.append("g").attr("transform", "translate(560,0)").call(d3.axisLeft(histY));
svg.append("g").attr("transform", "translate(0," + (height - 32) + ")").call(d3.axisBottom(histX));
var brush = d3.brush().extent([[0.0, 0.0], [512, 512]]).on("brush", brushed);
var imageRect = svg.append("g")
.attr("id", "image")
.selectAll("rect")
.data(cellData)
.enter()
.append("rect")
.attr("class", "selectable")
.attr("stroke", "lightgrey")
.attr("stroke-width", 1.0)
.attr("stroke-opacity", 0.5)
.style("fill", (d, flatIndex) => cellColor(d.density))
.attr("x", (d, flatIndex) => cellData[flatIndex].x[0])
.attr("y", (d, flatIndex) => cellData[flatIndex].y[0])
.attr("width", (d, flatIndex) => cellData[flatIndex].width[0])
.attr("height", (d, flatIndex) => cellData[flatIndex].height[0])
.each(d=>{d.selected=false});
svg.append("g")
.attr("id", "barchart")
.selectAll("rect")
.data([0, 0, 0])
.enter()
.append("rect")
.attr("x", (d, i) => histX(i))
.attr("y", d=> histY(d) + 32)
.attr("y", d=> height - 32 - histY(d))
.attr("width", histX.bandwidth())
.attr("fill", "");
yield svg.node();
svg.append("g")
.attr("class", "brush")
.call(brush)
.call(brush.move, [[0, 0], [512, 512]]);
yield svg.node();
let v = await Promises.delay(2500);
svg.select("g.brush")
.transition()
.duration(2500)
.call(brush.move, [[20, 20], [50, 50]]);
yield svg.node();
console.log("done")
}
Insert cell
{
var svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
var viewExtent = [[0, 0], [width, height]];
var cellData = kelvinHelmholtzAMR.cellData;
var cellPaths = kelvinHelmholtzAMR.cellPaths;
var tree = kelvinHelmholtzAMR.tree;
var cellColor = d3.scaleSequential(d3.interpolateGreys).domain([0.95, 2.15]);
var biggestCell = [d3.max(cellData, d=>d.width[0]), d3.max(cellData, d=>d.height[0])];
console.log("biggest", biggestCell);
svg.append("g")
.attr("id", "image")
.selectAll("rect")
.data(cellData)
.enter()
.append("rect")
.attr("class", "selectable")
.attr("stroke", "darkgrey")
.attr("stroke-width", 1.0)
.attr("stroke-opacity", 0.5)
.style("fill", (d, flatIndex) => cellColor(d.density))
.style("fill-opacity", 0.2)
.attr("x", (d, flatIndex) => cellData[flatIndex].x[0])
.attr("y", (d, flatIndex) => cellData[flatIndex].y[0])
.attr("width", (d, flatIndex) => cellData[flatIndex].width[0])
.attr("height", (d, flatIndex) => cellData[flatIndex].height[0])
.each(d=>{d.selected=false});
var line = d3.line()
.curve(d3.curveCatmullRom.alpha(0.5));
var myPath = svg.append("g")
.attr("id", "pathintegration")
.append("path")
.attr("d", line(myPoints))
.attr("stroke", "none")
.attr("display", "none")
.style("fill", "none").node();
yield svg.node();
var length = myPath.getTotalLength();
var Nsegments = 200;
var dt = length / Nsegments;
var pathSegments = d3.range(Nsegments).map( d => {
var segment = {x1: myPath.getPointAtLength(d * dt).x,
y1: myPath.getPointAtLength(d * dt).y,
x2: myPath.getPointAtLength((d+1) * dt).x,
y2: myPath.getPointAtLength((d+1) * dt).y,
i: d};
tree.visit(findOverlappingNodesPoint([segment.x2, segment.y2], biggestCell, nd => {
segment.density = nd.density;
segment.velocity_x = nd.velocity_x;
segment.velocity_y = nd.velocity_y;
segment.level;
}));
return segment;
});

var pathsegments = svg.append("g").attr("id", "pathsegments")
.selectAll("line")
.data(pathSegments)
.enter()
.append("line")
.attr("x1", d=>d.x1)
.attr("y1", d=>d.y1)
.attr("x2", d=>d.x2)
.attr("y2", d=>d.y2)
.style("stroke", "#7C4DFF")
.style("stroke-width", 2.0)
.style("fill", "#7C4DFF")
.style("stroke-opacity", 0.0)
.style("fill-opacity", 0.0);

var linePlotY = d3.scaleLinear()
.domain(d3.extent(pathSegments, d=>d.density))
.range([height - 32, 32]);
var linePlotX = d3.scaleLinear()
.domain([0, Nsegments])
.range([512 + 48, width - 64]);
svg.append("g").attr("transform", "translate(560,0)").call(d3.axisLeft(linePlotY));
svg.append("g").attr("transform", "translate(0," + (height - 32) + ")").call(d3.axisBottom(linePlotX));
var linequery = svg.append("g")
.attr("id", "linequery")
.selectAll("line")
.data(pathSegments.slice(1))
.enter()
.append("line")
.attr("fill", "#7C4DFF")
.attr("stroke", "#7C4DFF")
.attr("stroke-width", 1.5)
.style("stroke-opacity", 0.0)
.style("fill-opacity", 0.0)
.attr("x1", (d, i) => linePlotX(i-1))
.attr("x2", (d, i) => linePlotX(i))
.attr("y1", (d, i) => linePlotY(pathSegments[i].density))
.attr("y2", (d, i) => linePlotY(d.density));

var circle = svg
.append("circle")
.attr("cx", myPoints[0][0])
.attr("cy", myPoints[0][1])
.attr("r", 5.0)
.style("fill", "#2196F3");
var circleQuery = svg
.append("circle")
.attr("cx", linePlotX(0))
.attr("cy", linePlotY(pathSegments[0].density))
.attr("r", 5.0)
.style("fill", "#2196F3");
var lastPos = myPath.getPointAtLength(0.0);
for (var segi = 0; segi < Nsegments; segi++) {
var t = d3.transition().duration(10);
circle.transition(t)
.attr("cx", pathSegments[segi].x2)
.attr("cy", pathSegments[segi].y2);
pathsegments
.filter(d => (d.i <= segi))
.transition(t)
.style("fill-opacity", 1.0)
.style("stroke-opacity", 1.0);
circleQuery.transition(t)
.attr("cx", linePlotX(segi))
.attr("cy", linePlotY(pathSegments[segi].density));
linequery
.filter(d => (d.i <= segi))
.transition(t)
.style("fill-opacity", 1.0)
.style("stroke-opacity", 1.0);
await t.end();
yield svg.node();
}
}
Insert cell
import { createPaths, defaultConfig, createCells, ringermacherMead, rootGrid, refinedData, cfg, kelvinHelmholtzAMR, galaxy0030, kh, findOverlappingNodesRect, findOverlappingNodesPoint } from "@matthewturk/grid-cells";
Insert cell
myPoints = [[18, 13], [381, 79], [443, 228], [381, 331], [239, 338], [160, 183], [88, 316], [184, 441], [109, 491]];
Insert cell
height = Math.min(width, 500);
Insert cell
d3 = require("d3@5");
Insert cell
d3rect = require("d3-rect");
Insert cell
flubber = require("flubber");
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more