Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
chart = {
const zoomer = d3.zoom()
.on("zoom", null);
const svg = d3.create("svg")
.attr("title", data.barChartSVGTitle)
.attr("class", "svgWrapper")
.attr("width", width)
.attr("height", height)
.call(zoomer)
.on("wheel.zoom", scroll)
.on("mousedown.zoom", null)
.on("touchstart.zoom", null)
.on("touchmove.zoom", null)
.on("touchend.zoom", null);

const defs = svg.append("defs");

defs.append("clipPath")
.attr("id", "clip")
.call(clip);

svg.append("g")
.attr("class", "chart-title")
.call(chartTitle);
const mainGroup = svg.append("g")
.attr("class", "mainGroup");
const mainBarsGroup = mainGroup.append("g")
.attr("clip-path", "url(#clip)")
.attr("class", "mainBarsGroup");

const miniGroup = svg.append("g")
.attr("class", "miniGroup")
.attr("transform", "translate(" + minimapPositionTranslate + ")");
const brushGroup = svg.append("g")
.attr("class", "brushGroup")
.attr("transform", "translate(" + minimapPositionTranslate + ")")
.append("g")
.attr("class", "brush")
.call(brush);

brushGroup.selectAll("rect")
.attr("width", miniWidth);
brushGroup.call(brush.move, initialBrushXSelection);

const miniBars = miniGroup.selectAll(".bar")
.data(data, d => d.dayCount);
miniBars.enter().append("rect")
.attr("class", "bar")
.attr("x", d => miniXScale(d.x))
.attr("y", d => miniHeight - miniYScale(d.y))
.attr("width", miniXScale.bandwidth())
.attr("height", d => miniYScale(d.y))
.style("fill", barColor);

mainGroup.append("g")
.attr("class", "x-axis")
.call(mainXAxis);
const mainBars = mainBarsGroup.append("g")
.attr("class", "bars")
.selectAll("rect")
.data(data);
mainBars.join("rect")
.attr("role", "presentation")
.attr("class", "bar")
.attr("fill", barColor)
.attr("x", d => mainXScale(d.x))
.attr("y", d => mainHeight - mainYScale(d.y))
.attr("width", mainXScale.bandwidth())
.attr("height", d => mainYScale(d.y));

svg.append("g")
.call(chartBy)
return svg.node();
}
Insert cell
function update() {
const bar = d3.select(".mainBarsGroup").selectAll(".bar")
.data(data, d => d.dayCount);

bar
.attr("x", d => mainXScale(d.x))
.attr("y", d => mainHeight - mainYScale(d.y))
.attr("width", mainXScale.bandwidth())
.attr("height", d => mainYScale(d.y));

bar.exit()
.remove();
}
Insert cell
brush = d3.brushX()
.extent([[0, 0], [miniWidth, miniHeight]])
.on("brush", brushmove);
Insert cell
function brushmove() {
const extentX = d3.event.selection;
const selected = miniXScale
.domain()
.filter(d => (extentX[0] - miniXScale.bandwidth() + 1e-2 <= miniXScale(d)) && (miniXScale(d) <= extentX[1] - 1e-2));
d3.select(".miniGroup").selectAll(".bar")
.style("fill", d => selected.indexOf(d.x) > -1 ? barColor : inactiveColor);
d3.select(".mainGroup").select(".x-axis")
.call(mainXAxis);
let originalRange = mainXZoom.range();
mainXZoom.domain(extentX);

mainXScale.domain(data.map(d => d.x));
mainXScale.range([mainXZoom(originalRange[0]), mainXZoom(originalRange[1])]).paddingInner(0.4);

update();
}
Insert cell
function scroll() {
const gBrush = d3.select(".brush");

let selection = d3.brushSelection(gBrush.node());

let size = selection[1] - selection[0],
range = miniXScale.range(),
x0 = d3.min(range),
x1 = d3.max(range) + miniXScale.bandwidth(),
dx = -d3.event.deltaX,
topSection;

if (selection[0] - dx < x0) {
topSection = x0;
} else if (selection[1] - dx > x1) {
topSection = x1 - size;
} else {
topSection = selection[0] - dx;
}

d3.event.stopPropagation();
d3.event.preventDefault();

gBrush.call(brush.move, [topSection, topSection + size]);
}
Insert cell
Insert cell
Insert cell
clip = clipPath => clipPath.append("rect")
.attr("x", mainMargin.left)
.attr("y", mainMargin.top)
.attr("width", mainWidth + mainMargin.left)
.attr("height", mainHeight);
Insert cell
x = d3.scaleBand()
.domain(data.map(d => d.x))
.range([mainMargin.left, width - mainMargin.right])
.padding(0.1);
Insert cell
y = d3.scaleLinear()
.domain([0, d3.max(data, d => d.y)]).nice()
.range([mainMargin.top + mainHeight, mainMargin.top]);
Insert cell
mainXScale = d3.scaleBand()
.domain(data.map(d => d.x))
.range([mainMargin.left, width - mainMargin.right])
.paddingInner(0.4);
Insert cell
miniXScale = d3.scaleBand()
.domain(data.map(d => d.x))
.range([0, miniWidth])
.paddingInner(0.4);
Insert cell
mainYScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d.y)]).nice()
.range([0, mainHeight]);
Insert cell
miniYScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d.y)]).nice()
.range([0, miniHeight]);
Insert cell
mainXZoom = d3.scaleLinear()
.range([0, mainWidth])
.domain([0, mainWidth]);
Insert cell
mainXAxis = g => g
.attr("transform", `translate(0,${mainHeight})`)
.call(d3.axisBottom(mainXScale)
.tickSizeOuter(0)
.tickFormat(d => d3.timeFormat("%a")(d).substring(0, 1))
);
Insert cell
initialBrushXSelection = [0, 200]
Insert cell
chartTitle = g => g
.append("text")
.attr("id", "chart-title")
.attr("x", 0)
.attr("y", 0)
.attr("dy", "1em")
.style("font-weight", "800")
.style("font-size", "clamp(.7rem, 2.5vw, 1.2rem)") // minimum, preferred, maximum
.text(data.barChartTitle);
Insert cell
chartBy = g => g
.attr("transform", `translate(${width}, ${height})`)
.append("text")
.attr("id", "source")
.attr("x", 0)
.attr("y", 0)
.attr("dy", "-0.5em")
.attr("text-anchor", "end")
.text('@DiDoesDigital');
Insert cell
Insert cell
mainMargin = ({top: 48, right: 0, bottom: 24, left: 0})
Insert cell
mainWidth = width - mainMargin.left - mainMargin.right;
Insert cell
mainHeight = 450;
Insert cell
miniMargin = ({top: 12, right: 0, bottom: 48, left: 0})
Insert cell
miniHeight = 100;
Insert cell
miniWidth = width - miniMargin.left - miniMargin.right;
Insert cell
Insert cell
barColor = "#766FAE"
Insert cell
inactiveColor = "#E6E5F0"
Insert cell
activeColor = "#534e7a"
Insert cell
Insert cell
typographyStyles = html`<style>
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans:wght@400;700&display=swap');

text, table {
fill: #282541;
font: 400 16px/1.4 "Noto Sans", sans-serif;
}

.heading,
.paragraph {
fill: #282541;
font: 400 16px/1.4 "Noto Sans", sans-serif;
}
.heading {
font: 700 24px/1.4 "Noto Sans", sans-serif;
}
`
Insert cell
accessibleDataTable = render_data_table(data, {caption: data.tableCaption, columns: data.slice[0], focusable: false})
Insert cell
Insert cell
data[0]
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