Published
Edited
Dec 28, 2021
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
stringBoolConvert = stringBool => {
if (stringBool === 'True') return true
if (stringBool === 'False') return false
return null
}
Insert cell
firstOnionDate = new Date(2020, 9, 0)
Insert cell
Insert cell
scans = (await FileAttachment("scans.csv").csv()).map(scan => ({
...scan,
live: stringBoolConvert(scan.live),
onion_location_header: stringBoolConvert(scan.onion_location_header),
valid_https: stringBoolConvert(scan.valid_https),
downgrades_https: stringBoolConvert(scan.downgrades_https),
defaults_to_https: stringBoolConvert(scan.defaults_to_https),
hsts: stringBoolConvert(scan.hsts),
hsts_max_age: +scan.hsts_max_age,
hsts_entire_domain: stringBoolConvert(scan.hsts_entire_domain),
hsts_preload_ready: stringBoolConvert(scan.hsts_preload_ready),
hsts_preloaded: stringBoolConvert(scan.hsts_preloaded),
timestamp: d3.isoParse(scan.timestamp),
score: +scan.score
}))
Insert cell
Insert cell
scansByMonth = Array.from(d3.group(scans, d => d.site, d => d3.timeMonth.floor(d.timestamp)))
.map(
([name, months]) => Array.from(months).map(
([_, data]) => ({
name,
month: d3.timeMonth.floor(data[0].timestamp),
averageScore: d3.mean(data, d => d.score),
httpsValidMode: d3.mode(data, d => !!d.valid_https),
httpsDefaultMode: d3.mode(data, d => !!d.defaults_to_https),
hstsMode: d3.mode(data, d => !!d.hsts),
onionMode: d3.mode(data, d => !!d.onion_location_header),
})
)
).flat()
Insert cell
Insert cell
lineDotsLabel = (data, aggregator, color, label = '', rightLabelYOffset = 3, startDate = new Date(0)) => [
Plot.line(
data,
Plot.binX(
{ y: aggregator },
{ x: 'month', stroke: d => label, strokeWidth: 6, filter: d => +d.month > +startDate, thresholds: d3.timeMonth }
)
),
Plot.dot(
data,
Plot.binX(
{ y: aggregator },
{ x: 'month', fill: '#FFF', opacity: 0.5, filter: d => +d.month > +startDate, thresholds: d3.timeMonth, r: 3 }
)
),
Plot.text(
data,
Plot.selectLast(Plot.binX(
{ y: aggregator, text: g => d3.format('.0%')(aggregator(g)) + ' ' + label },
{
x: 'month',
dx: 5,
dy: rightLabelYOffset,
textAnchor: 'start',
stroke: '#FFF',
strokeWidth: 4,
fill: d => label,
fontWeight: 600,
fontSize: 12,
filter: d => +d.month > +startDate,
thresholds: d3.timeMonth
}
))
),
Plot.text(
data,
Plot.selectFirst(Plot.binX(
{ y: aggregator, text: g => d3.format('.0%')(aggregator(g)) },
{
x: 'month',
dx: -5,
dy: 3,
textAnchor: 'end',
fill: d => label,
stroke: '#FFF',
strokeWidth: 4,
fontWeight: 400,
filter: d => +d.month > +startDate,
thresholds: d3.timeMonth
}
))
)
]
Insert cell
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