Public
Edited
Apr 19, 2023
1 fork
Insert cell
Insert cell
richmond_data_organized_pop.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
// saving the data

df = FileAttachment("richmond_data_organized_pop.csv").csv({typed: true})

Insert cell
bar = {

const width = 800;
const height = 200;
const margin = ({top: 0, right: 20, bottom: 20, left: 20})
const axisColor = "#404040"


// create the container
const svg = d3.create("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);

// create x scale
const x = d3.scaleBand()
.domain(df.map(d => d.year))
.range([margin.left, width])
.padding(0.2)


// create y scale
const y = d3.scaleLinear()
.domain([0, d3.max(df, d => d.population)])
.range([height, margin.top])

// add x axis
const xAxisGroup = svg.append("g")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(x))
.attr("color", axisColor);

xAxisGroup.append("text")
.attr("x", width / 2)
.attr("y", margin.bottom - 5)
.attr("text-anchor", "middle")
.attr("font-size", 10)
.attr("font-family", "sans-serif")
.text("Year");

// add y axis
const yAxisGroup = svg.append("g")
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y))
.attr("color", axisColor);

yAxisGroup.append("text")
.attr("x", -margin.left)
.attr("y", height / 2)
.attr("text-anchor", "middle")
.attr("font-size", 10)
.attr("font-family", "sans-serif")
.text("Population");


// add the bars
svg.append("g")
.attr("id", "bars")
.selectAll('rect')
.data(df)
.join("rect")
.attr("width", x.bandwidth())
.attr("height", d => height - y(d.population))
.attr("y", d => y(d.population))
.attr("x", d => x(d.year))
.attr("fill", "lightgray")

//adding this for interaction later

svg.append("g").attr("id", "annotation");
return svg.node()

}
Insert cell
barWidth = 800
Insert cell
barHeight = 200
Insert cell
barMargin = ({top: 15, right: 15, bottom: 20, left: 20})
Insert cell
barX = d3.scaleBand()
.domain(df.map(d => d.year))
.range([barMargin.left, barWidth])
.padding(0.1)
Insert cell
barXAxis = g => g
.attr('transform', `translate(0, ${barHeight})`)
.call(d3.axisBottom()
.scale(barX)
.tickFormat(d3.timeFormat("%_d")))
Insert cell
barY = d3.scaleLinear()
.domain([0, d3.max(df, d => d.population) + 15])
.range([barHeight, barMargin.top])
Insert cell
barYAxis = g => g
.attr('transform', `translate(${barMargin.left}, 0)`)
.call(d3.axisLeft()
.scale(barY))
Insert cell
//interactivity 1
highlight_bars = {
let color = 'steelblue'
let rects = d3.select(bar).selection('g#bars').selectAll('rect')
rects.on('mouseover.highlight', function(d) {
let rect = d3.select(this)
rect.attr('fill', color)
})
rects.on('mouseout.highlight', function(d) {
let rect = d3.select(this)
rect.attr('fill', 'lightgray')
})
}
Insert cell
// Adding a tool-tip div
tool_tip = {
const tooltip = d3
.select("body")
.append("div")
.style("position", "absolute")
.style("visibility", "hidden")
.style("background", "white")
.style("padding", "5px")
.style("border", "1px solid #ccc");

// Adding events
svg
.append("g")
.attr("id", "bars")
.selectAll("rect")
.data(df)
.join("rect")
.attr("width", barX.bandwidth())
.attr("height", (d) => barHeight - barY(d.population))
.attr("y", (d) => barY(d.population))
.attr("x", (d) => barX(d.year))
.attr("fill", "lightgray")
// 2. Add mouseover and mouseout events to the bars
.on("mouseover", (event, d) => {
tooltip
.style("visibility", "visible")
// 3. Update the position and content of the tooltip
.style("left", event.pageX + 10 + "px")
.style("top", event.pageY - 10 + "px")
.text(`Year: ${d.year}, Population: ${d.population}`);
})
.on("mouseout", () => tooltip.style("visibility", "hidden"));
}

Insert cell
// interactivity 2

barsint = d3.select(bar).select("g#barsint").selectAll("bar");
Insert cell
annotations = d3.select(bar).select("g#annotation");
Insert cell
hover2 = {
const svg = d3.select(bar);


barsint.on("mouseover.hover2", function(df) {
let me = d3.select(this);
let div = d3.select("body").append("div");
div.attr("id", "details");
div.attr("class", "tooltip");
let rows = div.append("table")
.selectAll("tr")
.data(Object.keys(df))
.enter()
.append("year ");
rows.append("year").text(key => key);
rows.append("population").text(key => df[key]);
// show what we interacted with
d3.select(status).text("hover: " + df.df);
});

barsint.on("mousemove.hover2", function(d) {
let div = d3.select("div#details");
// get height of tooltip
let bbox = div.node().getBoundingClientRect();
div.style("left", d3.event.clientX + "px")
div.style("top", (d3.event.clientY - bbox.height) + "px");
});
barsint.on("mouseout.hover2", function(d) {
d3.selectAll("div#details").remove();
d3.select(status).text("hover: none");
});
return status;
}
Insert cell
//highlight with red border

highlight = {
const svg = d3.select(bar);
// event.namespace allows us to add multiple functions for one event
// only needed in examples like this where some events trigger multiple functions
barsint.on("mouseover.highlight", function(d) {
d3.select(this)
.raise() // bring to front
.style("stroke", "red")
.style("stroke-width", 2);
// show what we interacted with
d3.select(status).text("highlight: " + d.df);
});

barsint.on("mouseout.highlight", function(d) {
d3.select(this).style("stroke", null);
d3.select(status).text("highlight: none");
});
return status;
}
Insert cell
//intreaction 2...text

hoverText = {
const svg = d3.select(vis);
// used to test out interactivity in this cell
const status = html`<code>hoverText</code>`;

circles.on("mouseover.hoverText", function(d) {
let me = d3.select(this);
annotations.insert("text")
.attr("id", "label")
.attr("x", me.attr("cx"))
.attr("y", me.attr("cy"))
.attr("dy", r + 14)
.attr("text-anchor", "middle")
.text(d.codeword);

// show what we interacted with
d3.select(status).text("hover: " + d.df);
});

circles.on("mouseout.hover1", function(d) {
annotations.select("text#label").remove();
d3.select(status).text("hover: none");
});
return status;
}
Insert cell

gareen = {
const width = 800;
const height = 200;
const margin = { top: 20, right: 20, bottom: 20, left: 20 };
const axisColor = "#404040";

// create the container
const svg = d3
.create("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);

// create x scale
const x = d3
.scaleBand()
.domain(df.map((d) => d.year))
.range([margin.left, width])
.padding(0.2);

// create y scale
const y = d3
.scaleLinear()
.domain([0, d3.max(df, (d) => d.population)])
.range([height, margin.top]);

// add x axis
const xAxisGroup = svg.append("g")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(x))
.attr("color", axisColor);

xAxisGroup.append("text")
.attr("x", width / 2)
.attr("y", margin.bottom - 5)
.attr("text-anchor", "middle")
.attr("font-size", 10)
.attr("font-family", "sans-serif")
.text("Year");

// add y axis
const yAxisGroup = svg.append("g")
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y))
.attr("color", axisColor);

yAxisGroup.append("text")
.attr("x", -margin.left)
.attr("y", height / 2)
.attr("text-anchor", "middle")
.attr("font-size", 10)
.attr("font-family", "sans-serif")
.text("Population");

// add bars
svg
.append("g")
.attr("id", "bars")
.selectAll("rect")
.data(df)
.join("rect")
.attr("width", x.bandwidth())
.attr("height", (d) => height - y(d.population))
.attr("y", (d) => y(d.population))
.attr("x", (d) => x(d.year))
.attr("fill", "lightgray");

// adding this for interaction later
svg.append("g").attr("id", "annotation");

return svg.node();
}

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