Published
Edited
Mar 16, 2020
Kane County State's Attorney's race 2020 primary fundraising
Cook County State's Attorney Race 2020 campaign finance analysis
Insert cell
Insert cell
// This was run and then saved in the file attached in the `committees` variable to avoid load on the API
// committeesQuery = getData([35538, 35428, 35621], '2019-06-30', '2020-03-10')
Insert cell
committees = FileAttachment("committeesQuery.json").json()
Insert cell
breakpoint = 700
Insert cell
chartWidth = width
Insert cell
chartHeight = 0.4 * chartWidth
Insert cell
Insert cell
afeefDonors = donorTable(
committees[0],
"Democratic candidate Junaid Afeef has raised $55,993"
)
Insert cell
mosserTable = donorTable(committees[1])
Insert cell
spenceTable = donorTable(committees[2])
Insert cell
Insert cell
// This function should be moved into the pattern library ASAP
// function getData(committee_ids, startDate, endDate) {
// return committeeDetailsQuery(committee_ids, startDate, endDate).then(data => {
// return data.committees.map(d => {
// let cumulativeReceipts = d.filed_docs.length
// ? d.filed_docs[0].d2_reports[0].end_funds_available
// : 0;
// const startValue = {
// day: new Date(startDate),
// amount: 0,
// cumulative_amount: cumulativeReceipts
// };
// const receiptsByDay = Array.from(
// d3.rollup(
// d.receipts,
// v => d3.sum(v, r => r.amount),
// r => r.received_date
// )
// )
// .map(d => {
// cumulativeReceipts = cumulativeReceipts + d[1];
// return {
// day: new Date(d[0]),
// amount: d[1],
// cumulative_amount: cumulativeReceipts
// };
// })
// .sort((a, b) => a.day - b.day);
// const endValue = {
// day: new Date(endDate),
// amount: null,
// cumulative_amount:
// receiptsByDay[receiptsByDay.length - 1].cumulative_amount
// };
// return {
// ...d,
// receiptsByDay: [startValue, ...receiptsByDay, endValue],
// topDonors: Array.from(
// d3.rollup(
// d.receipts,
// v => d3.sum(v, r => r.amount),
// r => (r.first_name ? `${r.first_name} ${r.last_name}` : r.last_name)
// ),
// ([name, amount]) => ({ name, amount })
// ).sort((a, b) => b.amount - a.amount)
// };
// });
// });
// }
Insert cell
// import { committeeDetailsQuery } from "e8883a23e79eafb6"
Insert cell
function donorTable(d, label) {
const total = d3.sum(d.topDonors, d => d.amount);
const bigFormatter = d3.format(".1f");
const smallFormatter = d3.format(".3f");

const title = !label
? `${d.name} - $${parseInt(total).toLocaleString()} raised`
: label;

return html`<h2>${title}</h2>${HyperGrid(d.topDonors, {
tableHeight: 315,
columns: [
{
name: "Donor",
formatter: d => d.name,
width: "1fr"
},
{
name: "Donated since July 1, 2019",
formatter: d => d3.format("$.3~s")(d.amount),
width: ".7fr"
},
{
name: "Percent of total",
formatter: d => {
const pct = (100 * d.amount) / total;
const numFormatter = pct > .1 ? bigFormatter : smallFormatter;
return html`<div style="padding-right: 40px; position: relative;"><div style="color:#fff; height: 19px; width: ${pct}%; background-color: steelblue;"></div>
<div style="position: absolute; top: 0; right: 10px; /
max}%;">${numFormatter(pct)}%</div>
</div>`;
},
width: ".7fr"
}
]
})}`;
}
Insert cell
Insert cell
import { HyperGrid } from "@chicagoreporter/hypergrid"
Insert cell
d3 = require("d3", "d3-array")
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