Public
Edited
Mar 22, 2023
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
unTyped = FileAttachment("penguins_without_nan.csv").csv()
Insert cell
Insert cell
unTypedFirst = unTyped[0]
Insert cell
Insert cell
unTypedFirst.bill_depth_mm + unTypedFirst.bill_length_mm
Insert cell
Insert cell
penData = FileAttachment("penguins_without_nan.csv").csv({ typed: true })
Insert cell
Insert cell
manuData = {
const text = await FileAttachment("penguins_without_nan.csv").text();
return d3.csvParse(
text,
({
id,
species,
island,
bill_length_mm,
bill_depth_mm,
flipper_length_mm,
body_mass_g,
sex
}) => ({
id: parseInt(id),
species,
island,
bill_length_mm: parseFloat(bill_length_mm),
bill_depth_mm: parseFloat(bill_depth_mm),
flipper_length_mm: parseFloat(flipper_length_mm),
body_mass_g: parseFloat(body_mass_g),
sex
})
);
}
Insert cell
Insert cell
import { SummaryTable } from "@observablehq/summary-table"
Insert cell
viewof summary_data = SummaryTable(penData, { label: "Penguins Data" })
Insert cell
Insert cell
summary_data
Insert cell
viewof iris_data_summary = SummaryTable(
await FileAttachment("iris.csv").csv({ typed: true }),
{ label: "Iris Data" }
)
Insert cell
Insert cell
import { Wrangler, op } from "@observablehq/data-wrangler"
Insert cell
Insert cell
irisPart1 = FileAttachment("iris_part1.csv").csv({ typed: true })
Insert cell
irisPart2 = FileAttachment("iris_part2.csv").csv({ typed: true })
Insert cell
Insert cell
Wrangler(irisPart1, irisPart2)
Insert cell
Insert cell
combinedData = aq.from(irisPart1).union(aq.from(irisPart2)).objects() // Uncomment to return an array of objects
Insert cell
Insert cell
md`### Create SVG
`
Insert cell
htl.html`<svg width="300px" height="150px">
<circle cx="50" cy="50" r="20" fill="blue" transform="translate(50,0)"/>
<circle cx="100" cy="80" r="15" fill="red"/>
</svg>`
Insert cell
Insert cell
htl.html`<svg viewBox="0 0 600 300" width="300px" height="150px">
<circle cx="50" cy="50" r="20" fill="blue" transform="translate(50,0)"/>
<circle cx="100" cy="80" r="15" fill="red"/>
</svg>`
Insert cell
Insert cell
htl.html`<svg width="300px" height="150px">
<g transform="translate(50,0)">
<circle cx="50" cy="50" r="20" fill="blue" />
<circle cx="100" cy="80" r="15" fill="red"/>
</g>
</svg>`
Insert cell
Insert cell
Insert cell
Insert cell
htl.html`<svg style="width:450px; height:200px;">
${penData.map(
(d) =>
htl.svg`<circle cx="${d.bill_length_mm}" cy="${d.bill_depth_mm}" r="1"></circle>`
)}
</svg>`
Insert cell
maxBillLen = d3.max(penData, (d) => d.bill_length_mm)
Insert cell
maxBillDep = d3.max(penData, (d) => d.bill_depth_mm)
Insert cell
Insert cell
scatter = htl.html`<svg viewBox="0 0 ${maxBillLen + 2} ${
maxBillDep + 2
}" width="450" height="200">
${penData.map(
// Use data to position points and define add the CSS class 'p-point'
(d) =>
htl.svg`<circle class="p-point" cx="${d.bill_length_mm}" cy="${d.bill_depth_mm}" r="0.5"></circle>`
)}
</svg>`
Insert cell
Insert cell
style = html`
<style>
.p-point {
stroke: red;
stroke-width: 0.1px;
}
</style>`
Insert cell
Insert cell
Insert cell
svgSel = d3.select(scatter).selectAll("circle").style("fill", "#69b3a2")
Insert cell
svgSel.nodes()
Insert cell
Insert cell
import { Histogram } from "@d3/histogram"
Insert cell
penMass = penData.map((elem) => elem.body_mass_g)
Insert cell
Histogram(penMass)
Insert cell
Insert cell
Histogram(penMass, { width, height: 200, color: "steelblue" })
Insert cell
Insert cell
import { Scrubber } from "@mbostock/scrubber"
Insert cell
viewof mu = Scrubber(d3.ticks(-5, 5, 200), {
format: (x) => `mu = ${d3.format("+.2f")(x)}`,
autoplay: false,
alternate: true
})

Insert cell
randoms = Float64Array.from({ length: 2000 }, d3.randomNormal(mu, 2))
Insert cell
Histogram(randoms, {
width,
height: 200,
color: "steelblue",
domain: [-10, 10]
})
Insert cell
Insert cell
Insert cell
penAttr = Object.keys(penData[0])
.filter((a) => typeof penData[0][a] === "number")
.slice(1)
Insert cell
Insert cell
viewof xAttrName = Inputs.select(penAttr, {
label: "X Attribute",
value: penAttr[0]
})
Insert cell
viewof yAttrName = Inputs.select(penAttr, {
label: "Y Attribute",
value: penAttr[1]
})
Insert cell
height = 250
Insert cell
Insert cell
margin = ({ top: 20, rigth: 20, bottom: 20, left: 20 })
Insert cell
penData
Insert cell
{
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
const iWidth = width - margin.left - margin.rigth; // the actual width of the scatterplot
const iHeight = height - margin.top - margin.bottom; // the actual height of the scatterplot

// define axis: maps the available space to the datavalues
const xScale = d3
.scaleLinear()
.domain(d3.extent(penData, (d) => d[xAttrName]))
.range([0, iWidth])
.nice(); // creates axis with nice values and not fractions of values

// define axis: maps the available space to the datavalues
const yScale = d3
.scaleLinear()
.domain(d3.extent(penData, (d) => d[yAttrName]))
.range([0, iHeight])
.nice();

// add a group with all the circles and axes, which allows the traslation of all the elements
const g = svg
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);

// add a child g element to the current g element and execute (.call) a function on it to add the scale -> axis
g.append("g").call(d3.axisTop(xScale));
g.append("g").call(d3.axisLeft(yScale));

g.selectAll("circle")
.data(penData)
.join("circle")
.attr("cx", (d) => xScale(d[xAttrName]))
.attr("cy", (d) => yScale(d[yAttrName]))
.attr("r", 3);

return svg.node(); // retirn the svg node, otherwise the codeblock has no value
}
Insert cell
Insert cell
import { Legend, Swatches } from "@d3/color-legend"
Insert cell
Insert cell
Swatches(
d3.scaleOrdinal(
new Set(penData.map((e) => e.species)).values(),
d3.schemeCategory10
)
)
Insert cell
{
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
const iWidth = width - margin.left - margin.rigth;
const iHeight = height - margin.top - margin.bottom;

const xScale = d3
.scaleLinear()
.domain(d3.extent(penData, (d) => d[xAttrName]))
.range([0, iWidth])
.nice();

const yScale = d3
.scaleLinear()
.domain(d3.extent(penData, (d) => d[yAttrName]))
.range([iHeight, 0])
.nice();

// add color scale to encode the species property of the dataset
const cScale = d3
.scaleOrdinal(d3.schemeCategory10)
.domain(new Set(penData.map((e) => e.species)).values());

const g = svg
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);

g.append("g")
.attr("transform", `translate(0,${iHeight})`) // move the axis to the bottom
.call(d3.axisBottom(xScale));
g.append("g").call(d3.axisLeft(yScale));

g.selectAll("circle")
.data(penData)
.join("circle")
.attr("fill", (d) => cScale(d.species))
.attr("cx", (d) => xScale(d[xAttrName]))
.attr("cy", (d) => yScale(d[yAttrName]))
.attr("r", 3);

return svg.node();
}
Insert cell
Insert cell
alphabet = [..."ABCDEFGHIJKLMNOPQRSTUVWXYZ"]
Insert cell
Insert cell
chartStatic = {
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, 33])
.attr("font-family", "sans-serif")
.attr("font-size", 16);

svg
.selectAll("text")
.data(alphabet)
.join("text")
.attr("x", (d, i) => i * 17)
.attr("y", 17)
.attr("dy", "0.35em")
.text((d) => d);

return svg.node();
}
Insert cell
Insert cell
htl.html`<svg viewBox="0 0 ${width} 33" font-family="sans-serif" font-size="16">
${alphabet.map(
(d, i) => htl.svg`<text x="${i * 17}" y="17" dy="0.35em">${d}</text>`
)}
</svg>`
Insert cell
Insert cell
Insert cell
Insert cell
randomLetters = {
while (true) {
yield d3
.shuffle(alphabet.slice())
.slice(Math.floor(Math.random() * 10) + 5)
.sort(d3.acending);
await Promises.delay(3000);
}
}
Insert cell
chartDynamic = {
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, 33])
.attr("font-family", "sans-serif")
.attr("font-size", 16);

let text = svg.selectAll("text");

return Object.assign(svg.node(), {
update(letters) {
text = text
.data(letters)
.join("text")
.attr("x", (d, i) => i * 17)
.attr("y", 17)
.attr("dy", "0.35em")
.text((d) => d);
}
});
}
Insert cell
chartDynamic.update(randomLetters)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
chartDynamicKey = {
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, 33])
.attr("font-family", "sans-serif")
.attr("font-size", 16);

let text = svg.selectAll("text");

return Object.assign(svg.node(), {
update(letters) {
text = text
.data(letters, (d) => d)
.join(
(enter) =>
enter
.append("text")
.attr("y", 17)
.attr("dy", "0.35em")
.attr("fill", "green")
.text((d) => d),
(update) => update.attr("fill", "gray"),
(exit) => exit.remove()
)
.attr("x", (d, i) => i * 17);
}
});
}
Insert cell
chartDynamicKey.update(randomLetters)
Insert cell
Insert cell
chartDynamicAnimation = {
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, 33])
.attr("font-family", "sans-serif")
.attr("font-size", 16);

let text = svg.selectAll("text");

return Object.assign(svg.node(), {
update(letters) {
const t = svg.transition().duration(750);
text = text
.data(letters, (d) => d)
.join(
(enter) =>
enter
.append("text")
.attr("y", -7) // start position of new element
.attr("x", (d, i) => i * 17)
.attr("dy", "0.35em")
.attr("fill", "green")
.text((d) => d),
(update) => update.attr("fill", "black"),
(exit) =>
exit
.attr("fill", "red")
.call((text) => text.transition(t).attr("y", 41).remove())
)
.call((text) =>
text
.transition(t)
.attr("y", 17) // end position of each enter and update element
.attr("x", (d, i) => i * 17)
);
}
});
}
Insert cell
chartDynamicAnimation.update(randomLetters)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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