Public
Edited
Nov 14, 2023
Insert cell
Insert cell
houseMap = makeMap()
Insert cell
// variableColor is a flag for whether to show the gradient based on vote, true turns on gradient

function makeMap() {
var height = 150;
const svg = d3.select(DOM.svg(width, height));

var bar = createBarChart(svg, houseParsed, 0, 0, 1, width, 20, height);

// bar.selectAll(".vote-label-Democrats").text("52");
// bar.selectAll(".vote-label-Republicans").text("30");
return svg.node();
}
Insert cell
function createBarChart(
svg,
data,
x,
y,
scale,
screenWidth,
barHeight,
height
) {
var halfBarHeight = barHeight;
var group = svg.append("g");

// Domain is in, Range is out
const barChartScale = d3
.scaleLinear()
.domain([0, data.COUNT])
.range([0, screenWidth]);

const barChartColor = d3
.scaleOrdinal()
.domain([0, 1, 2, 3, 4, 5])
.range(["#0571b0", "#7ba0d9", "#FAF9F6", "#888888", "#f6a19a", "#cc3c28"]);

var lengthSoFar = 0;
console.log(data.data);

group
.selectAll("rect-rep")
.data(data.data)
.enter()
.append("rect") // Change "text" to "rect" to create a rectangle
.attr("y", height - 30)
.attr("x", (d, i) => totalPrevLength(i, data.data, barChartScale))
.attr("width", (d) => barChartScale(d)) // Set the width of the rectangle
.attr("height", barHeight) // Set the height of the rectangle
.attr("fill", (d, i) => barChartColor(i)); // Set the fill color of the rectangle

// add line in the middle
group
.append("path")
.attr(
"d",
d3.line()([
[width / 2, 0],
[width / 2, height]
])
)
.attr("stroke", "white")
.attr("stroke-width", 3);
// Make it dashed
// .style("stroke-dasharray", "7, 2");

//Add checkmarks
var republican = createCheckmarkGroup(
group,
width - 120,
height - 80,
1,
"Republicans",
data.GOPVOTES,
"#cc3c28",
true,
data.GOPWIN
);
var democrat = createCheckmarkGroup(
group,
70,
height - 80,
1,
"Democrats",
data.DEMVOTES,
"#0571b0",
false,
data.DEMWIN
);

// Apply a transformation to move and scale the entire group
group.attr("transform", `translate(${x}, ${y}) scale(${scale})`);

return group;
}
Insert cell
function totalPrevLength(num, data, barChartScale) {
var lengthSoFar = 0;
for (let index = 0; index < num; ++index) {
lengthSoFar += barChartScale(data[index]);
}
console.log("num", num, "lengthsofar", lengthSoFar);
return lengthSoFar;
}
Insert cell
function createCheckmarkGroup(
svg,
x,
y,
scale,
text,
votes,
fill,
swapBool,
checkBool
) {
// Create a group element
var group = svg.append("g");

// Append main text to the group
group
.append("text")
.attr("class", "checkmark-label")
.text(text)
.attr("x", 20)
.attr("y", 40)
.style("text-anchor", "end")
.attr("fill", fill || "#0571b0");

//Votes
group
.append("text")
.attr("class", "vote-label")
.text(votes)
.attr("x", -15)
.attr("y", 20)
.style("font-size", 72)
.style("text-anchor", "middle")
.attr("fill", fill || "#0571b0");

// Append checkmark to the group
group
.append("path")
.attr("d", checkmark)
.attr("class", "checkmark")
.attr("fill", fill || "#0571b0"); // Use the provided fill or default to "blue"

if (checkBool != true) {
group.select(".checkmark").attr("fill", "white");
}

if (swapBool) {
// Right Side
group.select(".checkmark-label").style("text-anchor", "start");
group.select(".checkmark").attr("transform", "translate(0, 30) scale(1)");
group
.select(".vote-label")
.attr("transform", "translate(125, 0) scale(1)")
.style("text-anchor", "end");
} else {
// Left Side
group.select(".checkmark").attr("transform", "translate(22, 30) scale(1)");
}
// Apply a transformation to move and scale the entire group
group.attr("transform", `translate(${x}, ${y}) scale(${scale})`);

group.attr("class", `check-group-${text}`);

group.select(".vote-label").attr("class", `vote-label-${text}`);
group.select(".checkmark").attr("class", `checkmark-${text}`);
group.select(".checkmark-label").attr("class", `checkmark-label-${text}`);

return group;
}
Insert cell
// variableColor is a flag for whether to show the gradient based on vote, true turns on gradient

test = {
var height = 400;
const svg = d3.select(DOM.svg(width, height));

var democrat = createCheckmarkGroup(
svg,
200,
200,
1,
"Republicans",
51,
"#0571b0",
true,
true
);

return svg.node();
}
Insert cell
houseParsed = {
return parseResults(houseResults);
}
Insert cell
senateParsed = {
return parseResults(senateResults);
}
Insert cell
function parseResults(data) {
var total = data.count;
var lean = data.RACE_STATUS.lean;
var called = data.RACE_STATUS.called;
var DEMWIN = false;
var GOPWIN = false;
var output = {
DEMCALLED: called.DEM,
DEMLEAN: lean.DEM,
LEANUNA: lean.UNA,
CALLEDUNA: called.UNA,
GOPLEAN: lean.GOP,
CALLEDGOP: called.GOP,
COUNT: total,
data: [called.DEM, lean.DEM, lean.UNA, called.UNA, lean.GOP, called.GOP],
order: [
"calledDEM",
"leanDEM",
"leanUNA",
"calledUNA",
"leanGOP",
"calledGOP"
],
DEMVOTES: called.DEM + lean.DEM,
GOPVOTES: called.GOP + lean.GOP,
DEMWIN: false,
GOPWIN: false
};
if (output.DEMVOTES > total / 2) {
output.DEMWIN = true;
} else {
output.DEMWIN = false;
}

if (output.GOPVOTES > total / 2) {
output.GOPWIN = true;
} else {
output.GOPWIN = false;
}
// var GOP = { lean: lean.dem, called: called.dem };
// var UNA = { lean: lean.dem, called: called.dem };

return output;
}
Insert cell
houseResults = {
return aggregateResults["2023-11-07-election-va-state-aggregate-feed_house"];
}
Insert cell
senateResults = {
return aggregateResults["2023-11-07-election-va-state-aggregate-feed_senate"];
}
Insert cell
// Grab aggregate results of Virginia from the Washington Post

aggregateResults = await d3.json(
"https://elex-page-data-prod.elections.aws.wapo.pub/results/2023-11-07-election-va-state-aggregate-feed.json"
)
Insert cell
checkmark = "M 7 10 L 0 3 L 3 0 L 7 4 L 14 -3 L 17 0 L 7 10" // SVG path for a check mark
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