Published
Edited
Mar 3, 2022
12 stars
Insert cell
Insert cell
Insert cell
chart = {
const svg = d3.select(DOM.svg(width, 1750));

const tooltip = d3.select("body").append("div").attr("class", "tooltip");

const path = svg
.append("path")
.attr(
"d",
`m110 80 ${lineWidth},0 0,80 -${lineWidth},0 0,80 ${lineWidth}, 0 0,80 -${lineWidth},0 0, 80 ${lineWidth},0 0,80 -${lineWidth},0 0,80 ${lineWidth}, 0 0,80 -${lineWidth},0 0, 80 ${lineWidth},0 0,80 -${lineWidth},0 0,80 ${lineWidth}, 0 0,80 -${lineWidth},0 0, 80 ${lineWidth},0 0,80 -${lineWidth},0 0,80 ${lineWidth}, 0 0,80 -${lineWidth},0 0, 80 ${lineWidth},0 0,80 -${lineWidth},0 0,80 ${lineWidth}, 0 0,80 -${lineWidth},0 0, 80 ${lineWidth}, 0`
)
.attr("stroke", "#ededed")
.attr("fill", "none")
.attr("stroke-width", 2);

const pathLength = path.node().getTotalLength();
const pathNode = path.node();

const t = svg.transition().duration(500);

const x = d3
.scaleLinear()
.domain(d3.extent(data, (d) => d.year))
.range([0, pathLength]);

const xYears = d3.scaleLinear().domain(years).range([0, pathLength]);

const dataNew = _.map(dataRaw, (d) => {
return {
...d,
year: +d.year,
xPos: pathNode.getPointAtLength(x(d.year)).x,
yPos: pathNode.getPointAtLength(x(d.year)).y,
color: colorScale(d.cat)
};
});

const uniqueDataCalc = _.map(uniqueData, (d) => {
return {
...d,
year: +d.year,
xPos: pathNode.getPointAtLength(x(d.year)).x,
yPos: pathNode.getPointAtLength(x(d.year)).y
};
});

const r = 5;

const simulation = d3
.forceSimulation(dataNew)
.force(
"x",
d3
.forceX()
.x((d) => d.xPos)
.strength(1)
)
.force(
"y",
d3
.forceY()
.y((d) => d.yPos)
.strength(0.8)
)
.force("collide", d3.forceCollide(r + 1))
.stop();

_.times(1000, () => {
simulation.tick();
});

// years
svg
.selectAll("text")
.data(uniqueDataCalc)
.join("text")
.attr("fill", "#cfcccc")
.attr("x", (d) => d.xPos - 17)
.attr("y", (d) => (d.year > 1939 ? d.yPos + 38 : d.yPos + 30))
.text((d) => d.year);

const circles = svg
.selectAll("circle")
.data(dataNew)
.join("circle")
.attr("cx", (d) => d.x)
.attr("cy", (d) => d.y)
.attr("r", r)
.attr("fill", (d) => d.color)
.attr("stroke", (d) =>
d.gender === "Female African American Firsts" ? "#3e1a24" : "#F8F8F8"
);

//tooltips

circles.on("mouseover", (event, d) => {
const current = event.currentTarget;
d3.select(current)
.raise()
.transition()
.attr("r", r + 3);
tooltip
.style("visibility", "visible")
.style("top", event.y + "px")
.style("left", event.x + "px")
.html(`<div>${d.person} </div> <div>..........<div/> <div>${d.accomplishment} </div>
`);
});

circles.on("mouseout", (event, d) => {
const current = event.currentTarget;
d3.select(current).transition().attr("r", r);
tooltip.style("visibility", "hidden");
});

return svg.node();
}
Insert cell
colorScale = d3.scaleOrdinal().domain(categories).range(colors)
Insert cell
categories = _.chain(data)
.map('cat')
.uniq('cat')
.value()
Insert cell
colors = ["#26192b", "#a770a0", "#d66e70", "#7376d0", "#89d3ab"]
Insert cell
lineWidth = width - 220
Insert cell
uniqueData = _.uniqBy(data, "year")
Insert cell
years = d3.range(1738, 2020)
Insert cell
data = _.map(dataRaw, (d) => {
return {
...d,
year: +d.year
};
})
Insert cell
// data source https://github.com/rfordatascience/tidytuesday/tree/master/data/2020/2020-06-09
Insert cell
dataRaw = FileAttachment("data@7.csv").csv({ typed: true })
Insert cell
style = html`
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Montaga&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Archivo+Black&family=Montserrat&display=swap" rel="stylesheet">
<style>

body, select, option, text {
font-family: 'Montserrat', sans-serif;
line-height: 1.5;
}

circle {
cursor: pointer;
}

h1, h2 {
font-family: 'Montaga', serif;
}

svg {
background: #F8F8F8;
}

.tooltip {
text-align: center;
color: #878787;
font-family: 'Montserrat', sans-serif;
font-size: 0.9rem;
max-width: 250px;
position: fixed;
background-color: #F8F8F8;
padding: 5px;
pointer-events: none;
transform: translate(-50%, -110%);
box-shadow: 1px 1px 5px rgb(204, 205, 207);
}

.tooltip.main-title {
color: "red"
}

img {

}

</style>
`
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