Public
Edited
Jun 22, 2023
3 forks
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
helloWorld = html`<p id='select-by-id'>Hello World!</p>`
Insert cell
Insert cell
myElement = d3.select('#select-by-id') // Refer to an ID of an element with a "#" at the beginning
Insert cell
Insert cell
myElement.text()
Insert cell
Insert cell
// myElement.text('Hello D3!') // 🛠️ Uncomment and run cell (Shift + Enter or click play button).
Insert cell
Insert cell
html`<ul class='select-by-class'>
<li>One</li>
<li>Two</li>
<li>Three</li>
<li>Four</li>
<li>Five</li>
</ul>`
Insert cell
Insert cell
// 🛠️ Uncomment the following lines (select lines, then Ctrl + Shift + /) and run cell (Shift + Enter or click play button).

// d3.select('.select-by-class') // Select the list element using the class attribute.
// .selectAll('li') // Select all list item elements.
// .text('Hello list!') // Change the text of each list item.
// .style('color', 'red') // Change the text color of each list item.
Insert cell
Insert cell
listOfDataValues = [10, 20, 30, 40, 50]
Insert cell
Insert cell
html`<ul id='data-list'><li>No connected data yet...</li></ul>`
Insert cell
Insert cell
// 🛠️ Uncomment the following lines (select lines, then Ctrl + Shift + /) and run cell (Shift + Enter or click blue play button).

// d3.select('#data-list') // Select the list element by its ID.
// .selectAll('li') // Select all list item elements that are children of the list element.
// .data(listOfDataValues) // Connect the data to the selection.
// .join('li') // For each data value, create or update the associated list item element.
// .text((d, i) => "The data at index #" + i + " is " + d) // Change the text of the list item based on the data value.
// .style("color", d => d > 30 ? "purple" : "black") // Change the text color of the list item based on the data value.
Insert cell
Insert cell
Insert cell
exampleDocument = html`
<!DOCTYPE html>
<html>
<body>
<svg width=200 height=200 style='border: 1px solid black'>
<circle cx=100 cy=100 r=50 fill='steelblue' stroke='black'/>
</svg>
</body>
</html>
`
Insert cell
Insert cell
html`<div id='container'>No SVG image added yet...</div>`
Insert cell
// 🛠️ Uncomment the following lines (select lines, then Ctrl + Shift + /) and run cell (Shift + Enter or click blue play button).

// {
// // Remove text and any previously added SVGs from container.
// d3.select("#container")
// .text('')
// .selectAll('svg')
// .remove();

// // Create the SVG image.
// const svg = d3.select("#container") // Select the HTML element that will contain the SVG image.
// .append("svg") // Append / create a new SVG image.
// .attr("width", 200) // Set the width of the image.
// .attr("height", 200) // Set the height of the image.
// .style("border", "1px solid black"); // Give the image an outline.

// svg.append("circle") // Add a circle to the SVG image.
// .attr("id", "mycircle") // Give the circle an ID so we can refer to it later.
// .attr("cx", 100) // Set the x center of the circle.
// .attr("cy", 100) // Set the y center of the circle.
// .attr("r", 50) // Set the radius of the circle.
// .style("fill", "purple") // Set the fill color of the circle.
// .style('stroke', 'black'); // The the outline color of the circle.

// return svg; // Return the svg image.
// }
Insert cell
Insert cell
// circle = d3.select("#mycircle") // 🛠️ Get a reference of the circle in the SVG image.
Insert cell
// circle.attr("r", 85); // 🛠️ Change the radius of the circle.
Insert cell
// circle.style("fill", "green"); // 🛠️ Change the fill color of the cirle.
Insert cell
Insert cell
barChartData = [50, 90, 120, 250, 200, 150, 100, 50, 10, 40, 80, 60, 40, 70, 50, 90, 120, 60, 40, 70, 50, 60, 40, 70]
Insert cell
Insert cell
chartWidth = width // The default value of "width" is the width of a notebook cell (if not overwritten elsewhere in the notebook)
Insert cell
chartHeight = 250;
Insert cell
Insert cell
{
// Calculate the sizing of the rectangles.
const barPadding = 5; // Space between rectangles.
const barWidth = chartWidth / barChartData.length; // Width of one bar / rectangle.
const maxValue = Math.max(...barChartData); // Maximum data value.

// Create the SVG image with the chosen width and height.
const svg = d3.create('svg')
.attr('width', chartWidth)
.attr('height', chartHeight);

// Create the bars / rectangles in the image.
svg.selectAll('rect') // Select all existing rectangles (even if there are none at first).
.data(barChartData) // Connect the data to the selection.
.join('rect') // Create a mapping between the data values and rectangles.
.attr('x', (d, i) => barWidth * i) // Set the horizontal position of the rectangle.
.attr('y', d => chartHeight - chartHeight * d / maxValue) // Set the vertical position of the rectangle.
.attr('width', barWidth - barPadding) // Set the rectangle width.
.attr('height', d => chartHeight * d / maxValue) // Set the rectangle height.
.style('fill', 'pink') // Set the rectangle fill color.
.style('stroke', 'black'); // Set the rectangle outline color.

// Return the HTML element of the SVG object.
return svg.node();
}
Insert cell
Insert cell
Insert cell
Insert cell
margin = ({ left: 30, top: 10, right: 10, bottom: 30 }) // Defines the area of the chart in the image.
Insert cell
Insert cell
yScale = d3.scaleLinear() // Get a linear scale object.
.domain([0, d3.max(barChartData)]) // Set input min / max (0 to max data value).
.range([chartHeight - margin.bottom, margin.top]) // Set output min / max (top and bottom edge of chart area).
Insert cell
Insert cell
dataValueInImageCoordinates = yScale(25) // Returns y position in pixels given a data value.
Insert cell
Insert cell
xScale = d3.scaleBand() // Get a scale object for discrete bands.
.domain(d3.range(barChartData.length)) // Set input min / max (0 to max data array index).
.range([margin.left, chartWidth - margin.right]) // Set output min / max (left to right edge of chart area).
.padding(0.1); // Set padding between bands.
Insert cell
Insert cell
dataIndexInImageCoordinates = xScale(5) // Returns x position in pixels given an index of the data array.
Insert cell
Insert cell
Insert cell
{
// Create the SVG image to draw the axis.
const width = 60; // Fixed width for vertical axis.
const svg = d3.select(DOM.svg(width, chartHeight)); // <- Shortcut for creating SVGs in Observable.

// 🧪 Experiment with other scales to see how the axis changes in the image. 🧪
// For example, try to set a different input domain.
// const yScale = d3.scaleLinear() // Get a linear scale object.
// .domain([0, 10]) // ⬅️ Set input min / max.
// .range([chartHeight - margin.bottom, margin.top]) // Set output min / max.
// Create the SVG elements for the axis.
svg.append('g') // Create a SVG group.
.call(d3.axisLeft(yScale)) // Call the D3 axis method.
.attr('transform', `translate(${margin.left}, 0)`); // Move the axis to the chart area.

// Return the HTML element of the SVG object.
return svg.node();
}
Insert cell
Insert cell
Insert cell
{
// Create the SVG image to draw the axis.
const height = 60; // Fixed height for horizontal axis.
const svg = d3.select(DOM.svg(chartWidth, height)); // <- Shortcut for creating SVGs in Observable.

// 🧪 Experiment with other scales to see how the axis changes in the image. 🧪
// For example, try to set a different input domain or padding.
// const xScale = d3.scaleBand() // Get a scale object for discrete bands.
// .domain(['One', 'Two', 'Three', 'Four', 'Five']) // ⬅️ Set input min / max.
// .range([margin.left, chartWidth - margin.right]) // Set output min / max (left to right edge of chart area).
// .padding(0.5); // Set padding between bands.
// Create the SVG elements for the axis.
svg.append('g') // Create a SVG group.
.call(d3.axisBottom(xScale)) // Call the D3 axis method for the group.
.attr('transform', `translate(0, ${height - margin.bottom})`); // Move the axis to the chart area.

// Return the HTML element of the SVG object.
return svg.node();
}
Insert cell
Insert cell
Insert cell
function createBarChart(width, height, margin, xScale, yScale, data) {
// Create the SVG.
const svg = d3.select(DOM.svg(width, height));
// Create and append the Y axis.
svg.append('g')
.attr('class', 'y-axis') // Give the axis a class name, so we can refer to it later (see excercise E2)
.attr('transform', `translate(${margin.left},0)`)
.call(d3.axisLeft(yScale));

// Create and append the X axis.
svg.append('g')
.attr('class', 'x-axis') // Give the axis a class name, so we can refer to it later (see excercise E2)
.attr('transform', `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(xScale));
// Create and join the bars / rectangles.
svg.selectAll('rect')
.data(data)
.join('rect')
.attr('x', (_, i) => xScale(i))
.attr('y', d => yScale(d))
.attr('width', xScale.bandwidth())
.attr('height', d => yScale(0) - yScale(d))
.style('stroke', 'black')
.attr('fill', 'pink');

return svg.node();
}
Insert cell
Insert cell
barChart = createBarChart(chartWidth, chartHeight, margin, xScale, yScale, barChartData)
Insert cell
Insert cell
Insert cell
Insert cell
// Returns a color given a normalized data value.
function getColorScale(schemeName) {
// Return D3's predefined color interpolator by name.
return d3[`interpolate${schemeName}`]
}
Insert cell
// An array of available color scheme names.
colorSchemeNames = ['Blues', 'Greens', 'Greys', 'Oranges', 'Purples', 'Reds', 'Inferno', 'Magma', 'Plasma', 'Warm', 'Cool', 'CubehelixDefault', 'BuGn', 'BuPu', 'GnBu', 'OrRd', 'PuBuGn', 'PuBu', 'PuRd', 'RdPu', 'YlGnBu', 'YlGn', 'YlOrBr', 'YlOrRd']
Insert cell
// Create a selection box to choose a color scheme by name.
viewof selectedColorSchemeName = Inputs.select(colorSchemeNames, {value: "RdPu", label: "Color scheme"})
Insert cell
// Create the color scale function.
colorScale = getColorScale(selectedColorSchemeName)
Insert cell
// Use the color scale function to turn normalized values into colors.
normalizedValueInColor = colorScale(0.5)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
yAxisLabel = '↑ Measured value'
Insert cell
xAxisLabel = 'Observation'
Insert cell
Insert cell
d3.create("text") // <- ⚠️ Use append instead of create when attaching the element to a selected axis.
.attr("x", chartWidth) // Set x position of label (e.g., at the right edge of the chart).
.attr("y", margin.bottom - 4) // Set y position of label (e.g., at the bootom edge of the chart).
.attr("fill", "currentColor") // Set text color.
.attr("text-anchor", "end") // Set text anchor.
.text("Example label for X-axis") // Set label text.
.node() // <- ⚠️ Only for preview, remove when attaching to the axis!
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import { alphabet as newDataset } from "@observablehq/plot-test-data"
Insert cell
newDataset
Insert cell
Insert cell
Insert cell
replay = Inputs.button("Animate circle!", { reduce: () => {
d3.select(animatedSvg) // Select the SVG.
.select('circle') // Select the circle.
.attr('cx', 20) // Reset the position.
.transition() // Add a transition.
.duration(2000) // Set the transition duration in milliseconds.
.attr('cx', width - 20); // Set the final value when the transition ends.
}})
Insert cell
animatedSvg = {
const svg = d3.select(DOM.svg(width, 50)) // Create an SVG.
.style("border", "1px solid black"); // Add a border.

const circle = svg.append('circle') // Append a circle.
.attr('cx', 20) // Set the x position.
.attr('cy', 25) // Set the y position.
.attr('r', 15) // Set the radius.
.style('fill', '#CBC3E3') // Set the fill color.
.style('stroke', 'black'); // Set the outline color.

yield svg.node(); // Return the HTML element.
}
Insert cell
Insert cell
temperatureAnomalyDataset = FileAttachment("HadCRUT5_global_annual.csv").csv({typed: true})
Insert cell
temperatureAnomalyValues = temperatureAnomalyDataset.map(d => d['Anomaly (deg C)'])
Insert cell
Insert cell
temperatureAnomalyRange = d3.extent(temperatureAnomalyValues)
Insert cell
Insert cell
scaleAnomalyPuOr = d3.scaleDiverging(t => d3.interpolateRdBu(1 - t)) // Invert interpolation value to get correct colors.
.domain([temperatureAnomalyRange[0], 0, temperatureAnomalyRange[1]]) // Set zero a mid point of color scale.
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
manipulatedData = ({ value: width / 5 }) // Initialize the data object (also sets the intial circle position).
Insert cell
Insert cell
Insert cell
Insert cell
colorInterpolators = colorSchemeNames.map(p => ({ name: p, interpolator: d3[`interpolate${p}`]}))
Insert cell
import {Legend} from "@d3/color-legend"
Insert cell
Insert cell
function duplicateSVG(originalNode, width, height) {
const original = d3.select(originalNode);
const other = original.clone(true);
const copy = d3.select(DOM.svg(original.attr('width'), original.attr('height')));
copy.append(() => other.node());
return copy.node();
}
Insert cell
Insert cell
function* drawGradient(colors, n = 256) {
// Create a new canvas with it's width set to the number of colors and it's height to one.
const ctx = DOM.context2d(n, 1, 1);
// Adjust the styling of the canvas to it is displayed larger.
ctx.canvas.style.width = "100%";
ctx.canvas.style.height = "40px";
ctx.canvas.style.imageRendering = "pixelated";
// Fill the canvas's pixels based on the given color function.
for (let i = 0; i < n; ++i) {
// For each color draw a colored rectangle in the size of a pixel.
ctx.fillStyle = colors(i / (n - 1));
ctx.fillRect(i, 0, 1, 1);
}

// Return the canvas.
yield ctx.canvas;
}
Insert cell
Insert cell
// Thanks to @gooostaw (https://stackoverflow.com/a/64456745)
function numberToLetters(num) {
let letters = '';
while (num >= 0) {
letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[num % 26] + letters;
num = Math.floor(num / 26) - 1;
}
return letters;
}
Insert cell
Insert cell
import { finalBarChart } from "@mroehlig/visualization-of-univariate-data-with-d3-solution"
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