Published
Edited
Apr 13, 2021
2 forks
1 star
Insert cell
Insert cell
viewof selectedTable = navio(tableData)
Insert cell
groupedData = d3.rollup(
selectedTable,
v => v.length,
d => d.object_type,
d => d.request_category
)
Insert cell
treeData = d3.hierarchy(groupedData)
Insert cell
treeData.leaves()
Insert cell
layTree = d3.tree().size([width, height])
Insert cell
layedOutTreeData = layTree(treeData)
Insert cell
layedOutTreeData.links()
Insert cell
objCopy = d => ({ x: d.x, y: d.y, name: d.data[0] })
Insert cell
stripedTreeData = layedOutTreeData.descendants().map(objCopy)
Insert cell
stripedLinksTreeData = layedOutTreeData
.links()
.map(l => ({ source: objCopy(l.source), target: objCopy(l.target) }))
Insert cell
{
const nodes = vl
.markCircle({ tooltip: true, size: 100 })
.encode(
vl
.x()
.fieldQ("x")
.axis(false),
vl
.y()
.fieldQ("y")
.scale({ reverse: true })
.axis(false)
)
.data(stripedTreeData);

const link = vl
.markRule({ tooltip: true, stroke: "#ccc" })
.encode(
vl
.x()
.fieldQ("source.x")
.axis(false),
vl.x2().field("target.x"),
vl
.y()
.fieldQ("source.y")
.scale({ reverse: true })
.axis(false),
vl.y2().field("target.y")
)
.data(stripedLinksTreeData);

return vl
.layer(link, nodes)
.width(width)
.render();
}
Insert cell
{
const svg = d3
.create("svg")
.attr("viewBox", [
-margin,
-margin,
width + margin * 2,
height + margin * 2
]);

svg
.selectAll(".link")
.data(layedOutTreeData.links())
.join("path")
.attr("class", "link")
.attr(
"d",
d3
.linkVertical()
.x(d => d.x)
.y(d => d.y)
)
.attr("fill", "none")
.attr("stroke", "#ccc");

svg
.selectAll(".node")
.data(layedOutTreeData)
.join("g")
.attr("class", "node")
.attr("transform", d => `translate(${d.x}, ${d.y})`)
.call(g =>
g
.append("circle")
.attr("r", 5)
.attr("fill", "#333")
)
.call(g => g.append("text").text(d => d.data[0]));

return svg.node();
}
Insert cell
{
const svg = d3
.create("svg")
.attr("viewBox", [
-margin,
-margin,
height + margin * 2,
width + margin * 2
])
.attr("width", height);

svg
.selectAll(".link")
.data(layedOutTreeData.links())
.join("path")
.attr("class", "link")
.attr(
"d",
d3
.linkHorizontal()
.x(d => d.y)
.y(d => d.x)
)
.attr("fill", "none")
.attr("stroke", "#ccc");

svg
.selectAll(".node")
.data(layedOutTreeData)
.join("g")
.attr("class", "node")
.attr("transform", d => `translate(${d.y}, ${d.x})`)
.call(g =>
g
.append("circle")
.attr("r", 5)
.attr("fill", "#333")
)
.call(g => g.append("text").text(d => d.data[0]));

return svg.node();
}
Insert cell
md`## Containment`
Insert cell
treeDataAggregated = d3.hierarchy(groupedData).sum(d => d[1])
Insert cell
layTreemap = d3
.treemap()
.size([width, height])
.round(true)
.padding(2)
Insert cell
layedOutTreemapData = layTreemap(treeDataAggregated.copy())
Insert cell
stripedTreemapData = layedOutTreemapData.leaves().map(objCopy2)
Insert cell
objCopy2 = d => ({
x0: d.x0,
x1: d.x1,
y0: d.y0,
y1: d.y1,
name: d.data[0],
value: d.value
})
Insert cell
vl
.markRect()
.encode(
vl
.x()
.fieldQ("x0")
.axis(false),
vl.x2().field("x1"),
vl
.y()
.fieldQ("y0")
.scale({ reverse: true })
.axis(false),
vl.y2().field("y1"),
vl.color().fieldN("name")
)
.data(stripedTreemapData)
.width(width)
.height(height)
.render()
Insert cell
swatches({color})
Insert cell
{
const svg = d3
.create("svg")
.attr("viewBox", [
-margin,
-margin,
width + margin * 2,
height + margin * 2
]);

svg
.selectAll(".node")
.data(layedOutTreemapData.leaves())
.join("g")
.attr("class", "node")
.attr("transform", d => `translate(${d.x0}, ${d.y0})`)
.call(g =>
g
.append("rect")
.attr("width", d => d.x1 - d.x0)
.attr("height", d => d.y1 - d.y0)
.attr("fill", d => color(d.data[0]))
)
.call(g =>
g
.append("text")
.attr("y", 10)
.call(text =>
text
.append("tspan")
.attr("x", 0)
.attr("dy", 0)
.text(d => d.data[0])
)
.call(text =>
text
.append("tspan")
.attr("x", 0)
.attr("dy", 10)
.text(d => d.data[1])
)
);

return svg.node();
}
Insert cell
layIcicle = d3
.partition()
.size([width, height])
.round(true)
.padding(1)
Insert cell
layedOutIcicleData = layIcicle(treeDataAggregated)
Insert cell
{
const svg = d3
.create("svg")
.attr("viewBox", [
-margin,
-margin,
width + margin * 2,
height + margin * 2
]);

svg
.selectAll(".node")
.data(layedOutIcicleData.descendants())
.join("g")
.attr("class", "node")
.attr("transform", d => `translate(${d.x0}, ${d.y0})`)
.call(g =>
g
.append("rect")
.attr("width", d => d.x1 - d.x0)
.attr("height", d => d.y1 - d.y0)
.attr("fill", d => color(d.data[0]))
)
.call(g =>
g
.append("text")
.attr("y", 10)
.call(text =>
text
.append("tspan")
.attr("x", 0)
.attr("dy", 0)
.text(d => d.data[0])
)
.call(text =>
text
.append("tspan")
.attr("x", 0)
.attr("dy", 10)
.text(d => d.value)
)
);

return svg.node();
}
Insert cell
layPack = d3
.pack()
.size([width, height])
.padding(1)
Insert cell
layedOutPackedData = layPack(treeDataAggregated.copy())
Insert cell
{
const svg = d3
.create("svg")
.attr("viewBox", [
-margin,
-margin,
width + margin * 2,
height + margin * 2
]);

svg
.selectAll(".node")
.data(layedOutPackedData.descendants())
.join("g")
.attr("class", "node")
.attr("transform", d => `translate(${d.x}, ${d.y})`)
.call(g =>
g
.append("circle")
.attr("r", d => d.r)
.attr("fill", d => color(d.data[0]))
)
.call(g =>
g
.append("text")
.attr("y", 10)
.call(text =>
text
.append("tspan")
.attr("x", 0)
.attr("dy", 0)
.text(d => d.data[0])
)
.call(text =>
text
.append("tspan")
.attr("x", 0)
.attr("dy", 10)
.text(d => d.value)
)
);

return svg.node();
}
Insert cell
color = d3
.scaleOrdinal()
.range(
d3.quantize(
t => d3.interpolateSpectral(t * .8 + .2),
new Set(tableData.map(d => d.request_category)).size
)
)
Insert cell
new Set(tableData.map(d => d.request_category)).size
Insert cell
html`<style>svg text { font-size: 8pt; font-family: sans-serif }</style>`
Insert cell
height = 400
Insert cell
margin = 20
Insert cell
url = "https://data.cityofberkeley.info/resource/bscu-qpbu.csv?$limit=10000"
Insert cell
tableData = loadSocrata(url, { progressive: false })
Insert cell
d3 = require("d3@6")
Insert cell
import { navio } from "@john-guerra/navio"
Insert cell
import { swatches } from "@d3/color-legend"
Insert cell
import { vl } from "@vega/vega-lite-api"
Insert cell
import { loadSocrata } from "@john-guerra/socrata-load-multiples-pages"
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