Public
Edited
Mar 13, 2023
Importers
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
mini_circle_fun = function(data, height=280) {
var arcScale = d3.scaleLinear().domain([0, 1000]).range([0, 2 * Math.PI]);
var data_with_zero = data.concat([{name: "Rest", value: 1000-data[0].value, icon: ""}])
console.log(data_with_zero);
return DonutChart(data_with_zero, {
name: d => d.name,
value: d => d.value,
innerRadius: height/3,
outerRadius: height/2,
width: height,
height: height,
title: d => "",
endAngle: 2 * Math.PI,
colors: [data[0].name == "Sleep" ? "#379149" : "#009CDE", "lightgrey"],
background: "white",
})
}
Insert cell
points = [{name: "Sleep", value: 200, icon: "💤"}, {name: "Activity", value: 500, icon: "🏃‍♀️"}]
Insert cell
population = FileAttachment("population-by-age.csv").csv({typed: true})
Insert cell
Insert cell
// Copyright 2021 Observable, Inc.
// Released under the ISC license.
// https://observablehq.com/@d3/donut-chart
function ArcChart(data, {
name = ([x]) => x, // given d in data, returns the (ordinal) label
value = ([, y]) => y, // given d in data, returns the (quantitative) value
title, // given d in data, returns the title text
width = 640, // outer width, in pixels
height = 400, // outer height, in pixels
innerRadius = Math.min(width, height) / 3, // inner radius of pie, in pixels (non-zero for donut)
outerRadius = Math.min(width, height) / 2, // outer radius of pie, in pixels
labelRadius = (innerRadius + outerRadius) / 2, // center radius of labels
format = ",", // a format specifier for values (in the label)
names, // array of names (the domain of the color scale)
colors, // array of colors for names
stroke = innerRadius > 0 ? "none" : "white", // stroke separating widths
strokeWidth = 1, // width of stroke separating wedges
strokeLinejoin = "round", // line join of stroke separating wedges
padAngle = stroke === "none" ? 1 / outerRadius : 0, // angular separation between wedges
startAngle = -Math.PI/2,
endAngle = Math.PI/2,
background = "white"
} = {}) {
// Compute values.
const N = d3.map(data, name);
const V = d3.map(data, value);
const I = d3.range(N.length).filter(i => !isNaN(V[i]));

// Unique the names.
if (names === undefined) names = N;
names = new d3.InternSet(names);

// Chose a default color scheme based on cardinality.
if (colors === undefined) colors = d3.schemeSpectral[names.size];
if (colors === undefined) colors = d3.quantize(t => d3.interpolateSpectral(t * 0.8 + 0.1), names.size);

// Construct scales.
const color = d3.scaleOrdinal(names, colors);

// Compute titles.
if (title === undefined) {
const formatValue = d3.format(format);
title = i => `${N[i]}\n${formatValue(V[i])}`;
} else {
const O = d3.map(data, d => d);
const T = title;
title = i => T(O[i], i, data);
}

// Construct arcs.
const arcs = d3.pie().startAngle(startAngle).endAngle(endAngle).padAngle(padAngle).sort(null).value(i => V[i])(I);
const arc = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius);
const arcLabel = d3.arc().innerRadius(labelRadius).outerRadius(labelRadius);
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [-width / 2, -height / 2, width, height])
.attr("style", `max-width: 100%; height: auto; height: intrinsic; background-color: ${background};`);

svg.append("g")
.attr("stroke", stroke)
.attr("stroke-width", strokeWidth)
.attr("stroke-linejoin", strokeLinejoin)
.selectAll("path")
.data(arcs)
.join("path")
.attr("fill", d => color(N[d.data]))
.attr("d", arc)
.attr("transform", d => `translate(0, ${height/2 - 10 })`)
.append("title")
.text(d => title(d.data));

svg.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 30)
.attr("text-anchor", "middle")
.selectAll("text")
.data(arcs)
.join("text")
// .attr("transform", d => `translate(${arcLabel.centroid(d)[0]}, ${arcLabel.centroid(d)[1]}+${height/2})`)
.attr("transform", d => `translate(${arcLabel.centroid(d)[0]}, ${arcLabel.centroid(d)[1]+height/2})`)
.selectAll("tspan")
.data(d => {
const lines = `${title(d.data)}`.split(/\n/);
return (d.endAngle - d.startAngle) > 0.25 ? lines : lines.slice(0, 1);
})
.join("tspan")
.attr("x", 0)
.attr("y", (_, i) => `${i * 1.1}em`)
.attr("font-weight", (_, i) => i ? null : "bold")
.text(d => d);

return Object.assign(svg.node(), {scales: {color}});
}
Insert cell
// Copyright 2021 Observable, Inc.
// Released under the ISC license.
// https://observablehq.com/@d3/donut-chart
function DonutChart(data, {
name = ([x]) => x, // given d in data, returns the (ordinal) label
value = ([, y]) => y, // given d in data, returns the (quantitative) value
title, // given d in data, returns the title text
width = 640, // outer width, in pixels
height = 400, // outer height, in pixels
innerRadius = Math.min(width, height) / 3, // inner radius of pie, in pixels (non-zero for donut)
outerRadius = Math.min(width, height) / 2, // outer radius of pie, in pixels
labelRadius = (innerRadius + outerRadius) / 2, // center radius of labels
format = ",", // a format specifier for values (in the label)
names, // array of names (the domain of the color scale)
colors, // array of colors for names
stroke = innerRadius > 0 ? "none" : "white", // stroke separating widths
strokeWidth = 1, // width of stroke separating wedges
strokeLinejoin = "round", // line join of stroke separating wedges
padAngle = stroke === "none" ? 1 / outerRadius : 0, // angular separation between wedges
startAngle = 0,
endAngle = 2 * Math.PI,
background = "white"
} = {}) {
// Compute values.
const N = d3.map(data, name);
const V = d3.map(data, value);
const I = d3.range(N.length).filter(i => !isNaN(V[i]));

// Unique the names.
if (names === undefined) names = N;
names = new d3.InternSet(names);

// Chose a default color scheme based on cardinality.
if (colors === undefined) colors = d3.schemeSpectral[names.size];
if (colors === undefined) colors = d3.quantize(t => d3.interpolateSpectral(t * 0.8 + 0.1), names.size);

// Construct scales.
const color = d3.scaleOrdinal(names, colors);

// Compute titles.
if (title === undefined) {
const formatValue = d3.format(format);
title = i => `${N[i]}\n${formatValue(V[i])}`;
} else {
const O = d3.map(data, d => d);
const T = title;
title = i => T(O[i], i, data);
}

// Construct arcs.
const arcs = d3.pie().startAngle(startAngle).endAngle(endAngle).padAngle(padAngle).sort(null).value(i => V[i])(I);
const arc = d3.arc().innerRadius(innerRadius).outerRadius(outerRadius);
const arcLabel = d3.arc().innerRadius(labelRadius).outerRadius(labelRadius);
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [-width / 2, -height / 2, width, height])
.attr("style", `max-width: 100%; height: auto; height: intrinsic; background-color: ${background};`);

svg.append("g")
.attr("stroke", stroke)
.attr("stroke-width", strokeWidth)
.attr("stroke-linejoin", strokeLinejoin)
.selectAll("path")
.data(arcs)
.join("path")
.attr("fill", d => color(N[d.data]))
.attr("d", arc)
// .attr("transform", d => `translate(0, ${height/2 - 10 })`)
.append("title")
.text(d => title(d.data));

svg.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 30)
.attr("text-anchor", "middle")
.selectAll("text")
.data(arcs)
.join("text")
.attr("transform", d => `translate(${arcLabel.centroid(d)[0]}, ${arcLabel.centroid(d)[1]})`)
.selectAll("tspan")
.data(d => {
const lines = `${title(d.data)}`.split(/\n/);
return (d.endAngle - d.startAngle) > 0.25 ? lines : lines.slice(0, 1);
})
.join("tspan")
.attr("x", 0)
.attr("y", (_, i) => `${i * 1.1}em`)
.attr("font-weight", (_, i) => i ? null : "bold")
.text(d => d);

return Object.assign(svg.node(), {scales: {color}});
}
Insert cell
import {howto} from "@d3/example-components"
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