Published
Edited
Jan 5, 2022
5 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
canvas = {
const perRow = 5;
const presidents = presData.length;
const imageWidth = width / perRow;
const imageHeight = imageWidth;
const svg = d3.create("svg").attr("viewBox", `0, 0, ${width}, ${presidents / perRow * imageHeight}`);
const g = svg.selectAll("g").data(presData).join("g");

g.attr(
"transform",
(d, i) => `translate(${(i % perRow) * imageWidth}, ${Math.floor(i / perRow) * imageWidth})`
);

if (!showColor) {
svg
.attr('filter', 'grayscale(100%)');
}
g.append("image")
.attr("href", (d) => d.image)
.attr("width", imageWidth)
.attr("height", imageHeight)
.attr("opacity", (d) => (100 - (d.dontKnow + d.haveNotHeard)) / 100)
.attr("preserveAspectRatio", "xMidYMin slice");

let textPadding = width > 768 ? 6 : 3;

if (showLabels) {
// BEGIN PERCENT TEXT
g.append("text")
.attr("x", imageWidth - textPadding)
.attr("y", textPadding)
.attr('dominant-baseline', 'hanging')
.attr('text-anchor', 'end')
.text((d, i) => i == 0 && width > 968 ?
`${100 - (d.dontKnow + d.haveNotHeard)}% know + have opinion` :
`${100 - (d.dontKnow + d.haveNotHeard)}%`)
.attr('fill', 'none')
.attr('stroke', 'black')
.attr('stroke-width', '2px')
.attr('stroke-linecap', 'round')
.attr('stroke-linejoin', 'round')
.attr('font-weight', '400')
// .attr('font-size', '1.5rem');
g.append("text")
.attr("x", imageWidth - textPadding)
.attr("y", textPadding)
.attr('dominant-baseline', 'hanging')
.attr('text-anchor', 'end')
.text((d, i) => i == 0 && width > 968 ?
`${100 - (d.dontKnow + d.haveNotHeard)}% know + have opinion` :
`${100 - (d.dontKnow + d.haveNotHeard)}%`)
.attr('font-weight', '400')
.attr('fill', 'white')
// .attr('font-size', '1.5rem');
// BEGIN INITIALS TEXT
g.append("text")
.attr("x", textPadding)
.attr("y", imageHeight - textPadding)
// .attr('dominant-baseline', 'hanging')
.attr('text-anchor', 'start')
.text(d => d.initials)
.attr('fill', 'none')
.attr('stroke', 'black')
.attr('stroke-width', '2px')
.attr('stroke-linecap', 'round')
.attr('stroke-linejoin', 'round')
.attr('font-weight', '400')
// .attr('opacity', (d) => (100 - (d.dontKnow + d.haveNotHeard)) / 100)
.attr('font-size', '1.5rem');
g.append("text")
.attr("x", textPadding)
.attr("y", imageHeight - textPadding)
// .attr('dominant-baseline', 'hanging')
.attr('text-anchor', 'start')
.text(d => d.initials)
.attr('font-weight', '400')
.attr('fill', 'white')
// .attr('opacity', (d) => (100 - (d.dontKnow + d.haveNotHeard)) / 100)
.attr('font-size', '1.5rem');
}
return svg.node();
}
Insert cell
presData = rawPresidentData.map(d => {
return {
name: d.Name,
initials: d.Name.split(' ')
.map(d => d[0])
.join(''),
veryFav: d['Very Favorable %'],
someFav: d['Somewhat Favorable %'],
someUnfav: d['Somewhat Unfavorable %'],
veryUnfav: d['Very Unfavorable %'],
dontKnow: d['Don’t know %'],
haveNotHeard: d['Have not heard of them %'],
date: d['First Inauguration Date'],
image: d['Portrait URL']
};
})
Insert cell
rawPresidentData = FileAttachment("us-president-favorability.csv").csv({
typed: true
})
Insert cell
html`<style>
@media screen and (max-width: 768px) {
text {
font-size: .85rem;
}
}
@media screen and (max-width: 568px) {
text {
font-size: .65rem;
}
}
</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