Public
Edited
May 23, 2023
Insert cell
Insert cell
chart = BarChart(lengthArray, {
x: d => d.species,
y: d => d.avg_beak_length,
xDomain: d3.groupSort(lengthArray, ([d]) => d.avg_beak_length, d => d.species), // sort by increasing avg beak depth
// yFormat: "%",
yLabel: "Average Beak Length (mm)",
width: 400,
height: 600,
color: "darkmagenta"
})
Insert cell
penguins = FileAttachment("penguins.json").json()
Insert cell
lengthArray = {
function aggreg() {
const map = new Map();
// As it turns out, d3.group(penguins, d => d["Species"]) does the same thing as this for loop
for (let i = 0; i < penguins.length ; i++) { // check length property of array
let species = penguins[i]["Species"];
if (!map.has(species)) { // make sure entries are setup before pushing elements
map.set(species, []);
}
if (penguins[i]["Beak Length (mm)"]) {
//push on the beak depth of each species
map.get(species).push(penguins[i]["Beak Length (mm)"]);
}
}
let penguinArray = [];
for (let key of map.keys()) {
let values = map.get(key);
penguinArray.push({
//group 3 species together
species: key,
//mean of the beak depth of each species
avg_beak_length: d3.mean(values) // use values array directly, not a function
})
}
return penguinArray;
}
return aggreg();
}
Insert cell
Insert cell
x = (d, i) => i // given d in data, returns the (ordinal) x-value
Insert cell
y = d => d // given d in data, returns the (quantitative) y-value
Insert cell
function title(data) {
title // given d in data, returns the title text
}
Insert cell
// function xComponents(data) {
// marginLeft = 40, // the left margin, in pixels
// marginRight = 0, // the right margin, in pixels
// width = 640, // the outer width of the chart, in pixels
// xRange = [marginLeft, width - marginRight] // [left, right]
// }
Insert cell
height = 400 // the outer height of the chart, in pixels
Insert cell
// function margins (data, {
// marginTop = 20, // the top margin, in pixels
// marginBottom = 30, // the bottom margin, in pixels
// height = 400, // the outer height of the chart, in pixels
// yRange = [height - marginBottom, marginTop], // [bottom, top]
// yScale = yType(yDomain, yRange),
// yAxis = d3.axisLeft(yScale).ticks(height / 40, yFormat)
// } = {} ) {}
Insert cell
marginTop = 20 // the top margin, in pixels
Insert cell
marginBottom = 30 // the bottom margin, in pixels
Insert cell
marginLeft = 40 // the left margin, in pixels
Insert cell
marginRight = 0 // the right margin, in pixels
Insert cell
width = 640 // the outer width of the chart, in pixels
Insert cell
xRange = [marginLeft, width - marginRight] // [left, right]
Insert cell
function xDomain (data) {
xDomain // an array of (ordinal) x-values
}
Insert cell
yType = d3.scaleLinear // linear relationship between input and output
Insert cell
function yDomain(data) {
yDomain // [ymin, ymax]
}
Insert cell
yRange = [height - marginBottom, marginTop] // [bottom, top]

Insert cell
xPadding = 0.1 // amount of x-range to reserve to separate bars
Insert cell
function yFormat(data) {
yFormat // a format specifier string for the y-axis
}
Insert cell
function yLabel(data) {
yLabel // a label for the y-axis
}
Insert cell
color = "currentColor" // bar fill color
Insert cell
function values(data) {
// Compute values.
const X = d3.map(data, x);
const Y = d3.map(data, y);
}
Insert cell
function omit (data, X) {
// Omit any data not present in the x-domain.
const I = d3.range(X.length).filter(i => xDomain.has(X[i]));
}
Insert cell
// Compute default domains, and unique the x-domain.
function domains(xDomain, yDomain, X, Y) {
if (xDomain === undefined) xDomain = X;
if (yDomain === undefined) yDomain = [0, d3.max(Y)];
xDomain = new d3.InternSet(xDomain);
}
Insert cell
function scaleAxesFormat() {
// Construct scales, axes, and formats.
const xScale = d3.scaleBand(xDomain, xRange).padding(xPadding);
// const yScale = yType(yDomain, yRange);
const xAxis = d3.axisBottom(xScale).tickSizeOuter(0);
// const yAxis = d3.axisLeft(yScale).ticks(height / 40, yFormat);
}
Insert cell
function makeTitle(data, title, yScale, X, Y, bar) {
// Compute titles.
if (title === undefined) {
const formatValue = yScale.tickFormat(100, yFormat);
title = i => `${X[i]}\n${formatValue(Y[i])}`;
} else {
//array of data entires
const O = d3.map(data, d => d);
//reference to the original title function
const T = title;
//given index i calls that entry from the original entry set
title = i => T(O[i], i, data);
}
if (title) bar.append("title")
.text(title);
}
Insert cell

// Copyright 2021 Observable, Inc.
// Released under the ISC license.
// https://observablehq.com/@d3/bar-chart
function BarChart(data, scaleAxesFormat,{
x = (d, i) => i, // given d in data, returns the (ordinal) x-value
y = d => d, // given d in data, returns the (quantitative) y-value
title, // given d in data, returns the title text
xDomain, // an array of (ordinal) x-values
yDomain, // [ymin, ymax]
yFormat, // a format specifier string for the y-axis
yLabel, // a label for the y-axis
color = "currentColor" // bar fill color
} = {}) {
//Compute values.
const X = d3.map(data, x);
const Y = d3.map(data, y);

// Compute default domains, and unique the x-domain.
if (xDomain === undefined) xDomain = X;
if (yDomain === undefined) yDomain = [0, d3.max(Y)];
xDomain = new d3.InternSet(xDomain);

// Omit any data not present in the x-domain.
const I = d3.range(X.length).filter(i => xDomain.has(X[i]));

//Construct scales, axes, and formats.
const xScale = d3.scaleBand(xDomain, xRange).padding(xPadding);
const yScale = yType(yDomain, yRange);
const xAxis = d3.axisBottom(xScale).tickSizeOuter(0);
const yAxis = d3.axisLeft(yScale).ticks(height / 40, yFormat);

const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.attr("style", "max-width: 100%; height: auto; height: intrinsic;");

svg.append("g")
.attr("transform", `translate(${marginLeft},0)`)
.call(yAxis)
.call(g => g.select(".domain").remove())
.call(g => g.selectAll(".tick line").clone()
.attr("x2", width - marginLeft - marginRight)
.attr("stroke-opacity", 0.1))
.call(g => g.append("text")
.attr("x", -marginLeft)
.attr("y", 10)
.attr("fill", "currentColor")
.attr("text-anchor", "start")
.text(yLabel));

const bar = svg.append("g")
.attr("fill", color)
.selectAll("rect")
.data(I)
.join("rect")
.attr("x", i => xScale(X[i]))
.attr("y", i => yScale(Y[i]))
.attr("height", i => yScale(0) - yScale(Y[i]))
.attr("width", xScale.bandwidth());

if (title) bar.append("title")
.text(title);

svg.append("g")
.attr("transform", `translate(0,${height - marginBottom})`)
.call(xAxis);

return svg.node();
}
Insert cell
import {aq, op} from "@uwdata/arquero"
Insert cell
import {printTable} from "@uwdata/data-utilities"
Insert cell
import {howto, altplot} from "@d3/example-components"
Insert cell
// chartDepth = BarChart(depthArray, {
// x: d => d.species,
// y: d => d.avg_beak_length,
// xDomain: d3.groupSort(depthArray, ([d]) => d.avg_beak_depth, d => d.species), // sort by increasing avg beak depth
// //yFormat: "%",
// yLabel: "Average Beak Depth (mm)",
// width: 400,
// height: 600,
// color: "maroon"
// })
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