Public
Edited
Feb 1, 2023
Insert cell
Insert cell
update = {
const mychart = Chart()
.width(chartWidth)
.height(500)
.x("Horsepower")
.y("Acceleration");

d3.select(base)
.datum(data)
.call(mychart);
}
Insert cell
Insert cell
Insert cell
base = {
const base = d3.create("div");

return base.node();
}
Insert cell
function Chart() {
const margin = { left: 40, top: 20, bottom: 20, right: 20 };

let x = d3.scaleLinear(),
y = d3.scaleLinear(),
xAttr = "x",
yAttr = "y",
id = null,
width = 600,
height = 500,
onBrush = filtered => {
console.log("sel", filtered);
};

const brush = d3.brush();

function updateBrush(sel, data) {
function brushed(event) {
const selection = event.selection;
if (selection) {
const [[x0, y0], [x1, y1]] = selection;

const isSelected = d =>
x(d[xAttr]) >= x0 &&
x(d[xAttr]) <= x1 &&
y(d[yAttr]) >= y0 &&
y(d[yAttr]) <= y1;

const filteredData = data.filter(isSelected);
onBrush(filteredData);

sel
.selectAll(".item")
.style("fill", "steelblue")
.filter(isSelected)
.style("fill", "red");
}
}

brush
.extent([
[0, 0],
[
width - margin.left - margin.right,
height - margin.top - margin.bottom
]
])
.on("start brush end", brushed);

sel.select(".brush").call(brush);
}

// A good rule of thumb is that your appends should go here
const onEnter = enter => {
const svgEnter = enter.append("svg");

const g = svgEnter.append("g").attr("class", "gDrawing");
g.append("g")
.attr("class", "x-axis")
.append("text")
.attr("class", "axisLabel");
g.append("g")
.attr("class", "y-axis")
.append("text")
.attr("class", "axisLabel");

g.append("g").attr("class", "marks");

g.append("g").attr("class", "brush");

return svgEnter;
};
const onUpdate = update => update;
const onExit = exit => exit.remove();

function chart(sel) {
sel.each(data => {
const iwidth = width - margin.left - margin.right,
iheight = height - margin.top - margin.bottom;

const svg = sel
.selectAll("svg")
.data([data])
.join(onEnter, onUpdate, onExit)
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height);
const g = svg
.select("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`);

x.domain(d3.extent(data, d => d[xAttr])).range([0, iwidth]);
y.domain(d3.extent(data, d => d[yAttr])).range([iheight, 0]);

updateBrush(sel, data);

// *** Transition ***
const t = g.transition().duration(750);
// Observable only, stop the animation if it isn't done and the cell is disposed
invalidation.then(() => svg.interrupt(t));

// ***** Axis ******
g.select(".x-axis")
.attr("transform", `translate(0, ${iheight})`)
.transition(t)
.call(d3.axisBottom(x).ticks(3));
g.select(".x-axis")
.select(".axisLabel")
.style("fill", "black")
.attr("transform", `translate(${iwidth}, -10)`)
.style("text-anchor", "end")
.text(xAttr);

g.select(".y-axis")
.transition(t)
.call(d3.axisLeft(y).ticks(3));
g.select(".y-axis")
.select(".axisLabel")
.style("fill", "black")
.style("text-anchor", "middle")
.attr("transform", `translate(0, -10)`)
.text(yAttr);

// ****** Marks ******
const moveItems = item =>
item.attr("cx", d => x(d[xAttr])).attr("cy", d => y(d[yAttr]));
g.select(".marks")
.selectAll(".item")
.data(data, (d, i) => (id !== null ? d[id] : i))
.join(
enter =>
enter
.append("circle")
.attr("class", "item")
.call(moveItems),
update => update.call(update => update.transition(t).call(moveItems))
)
.attr("r", 2)
.style("fill", "steelblue");
});
}

chart.x = function(_) {
if (!arguments.length) return xAttr;
xAttr = _;
return chart;
};
chart.y = function(_) {
if (!arguments.length) return yAttr;
yAttr = _;
return chart;
};
chart.width = function(_) {
if (!arguments.length) return width;
width = _;
return chart;
};
chart.height = function(_) {
if (!arguments.length) return height;
height = _;
return chart;
};
chart.id = function(_) {
if (!arguments.length) return id;
id = _;
return chart;
};
chart.onBrush = function(_) {
if (!arguments.length) return onBrush;
onBrush = _;
return chart;
};

return chart;
}
Insert cell
Insert cell
splom = {
const target = html`<div>`;

d3.select(target)
.selectAll("div")
.data(quants)
.join("div")
// Using each so I can access the row and column attribs
.each(function(rowAt) {
d3.select(this)
.selectAll("span")
.data(quants)
.join("span")
.each(function(colAt) {
console.log(rowAt, colAt);

// Then draw the chart in here
d3.select(this)
.datum(data)
.call(
Chart()
.width((width * .9) / quants.length)
.height((width * .9) / quants.length)
.x(rowAt)
.y(colAt)
);
});
});

return target;
}
Insert cell
quants = Object.keys(data[0]).filter(at => typeof data[0][at] === "number")
Insert cell
data = vegaDatasets["cars.json"]()
Insert cell
vegaDatasets = require("vega-datasets@2")
Insert cell
d3 = require("d3@6")
Insert cell
import { slider } from "@jashkenas/inputs"
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